类型提示协议的附加属性?
Type hinting additional attribute of a protocol?
是否可以键入提示 class 的属性的附加属性?
我有一个 class 属性 Outer.inner
,它可以是符合协议 InnerProto
.
的 class 的任何实例
#### I do not control this code #######
from typing import Protocol
class InnerProto(Protocol):
arg: int
class OuterProto(Protocol):
inner: InnerProto
Inner
class符合协议InnerProto
,但它还有一个额外的属性(据我了解,这不违反协议一致性)
class Outer:
def __init__(self, inner: InnerProto):
self.inner: InnerProto = inner
class Inner:
def __init__(self, arg: int):
self.arg: int = arg # this is part of the protocol
self.arg2: int = arg # this is not
Pycharm (v2021.2) 检查将属性 arg2
突出显示为未解析的属性。
def test_type_hint_example():
obj = Outer(Inner(1))
assert obj.inner.arg == 1
assert obj.inner.arg2 == 1 # inspection highlights arg2 as "unresolved attribute"
是否可以输入提示以便检查识别 arg2 是什么?
通常我会倾向于更改 Outer.inner
的类型提示,但在这种情况下那将是一个错误。 inner
可以是任何符合 InnerProto
.
的 class
我的第二个想法是覆盖实例属性的类型提示。这种类型的技巧对非属性对象有效,但在这种情况下会导致不同的检查错误:“Non-self attribute could not be type hinted”
def test_option1():
obj = Outer(Inner(1))
obj.inner: Inner # fixes inspection for arg2, but "Non-self attribute could not be type hinted" occurs
assert obj.inner.arg == 1
assert obj.inner.arg2 == 1
还有哪些其他选择?
我认为这里的问题是代码不是类型安全的。
您的 Outer.__init__
函数是:
class Outer:
def __init__(self, inner: InnerProto):
self.inner = inner
# <-- snip -->
您用 InnerProto
注释了 inner
参数。这意味着 Outer.inner
属性可以是 任何 类型,只要该类型符合 InnerProto
协议。
根据您的说法,这是正确的类型提示:
Normally I would be inclined to alter the type hint of Outer.inner
but in this case that would be a mistake. inner
can be ANY class that conforms to InnerProto
.
如果是这种情况,则静态类型检查器无法验证 Outer.inner
是否具有 InnerProto
中未指定的任何属性或方法。这就是类型检查器在您的 test_type_hint_example
函数中引发错误的原因:您已经告诉类型检查器 Outer.inner
可以是任何类型,只要该类型符合 InnerProto
,但是 InnerProto
没有说明 arg2
属性,而且并非所有 python 类型都具有 arg2
属性,因此您可能会得到 AttribiteError
当你访问 Outer.inner.arg2
.
如果您确定,在这个特定函数的上下文中,Outer.inner
将是Inner
,因此可以保证具有 arg2
属性——尽管事实上在大多数情况下,Outer.inner
“可以是任何符合 InnerProto
的 class” — 然后你可以像这样使用 typing.cast
:
from typing import cast
def test_type_hint():
obj = Outer(Inner(1))
inner = cast(Inner, obj.inner)
assert inner.arg == 1
assert inner.arg2 == 1
然而,实际上,如果您 确定 Outer.inner
可以保证具有 arg2
属性,则很可能表明您确实,实际上, Outer.inner
的类型提示错误(如果不查看更多代码库,很难告诉您正确的类型提示是什么)。以我上面刚刚演示的方式使用 typing.cast
通常只能作为最后的手段使用——它更像是一种逃避类型检查的方法,从长远来看这对你没有帮助 运行如果您的代码不是类型安全的。
是否可以键入提示 class 的属性的附加属性?
我有一个 class 属性 Outer.inner
,它可以是符合协议 InnerProto
.
#### I do not control this code #######
from typing import Protocol
class InnerProto(Protocol):
arg: int
class OuterProto(Protocol):
inner: InnerProto
Inner
class符合协议InnerProto
,但它还有一个额外的属性(据我了解,这不违反协议一致性)
class Outer:
def __init__(self, inner: InnerProto):
self.inner: InnerProto = inner
class Inner:
def __init__(self, arg: int):
self.arg: int = arg # this is part of the protocol
self.arg2: int = arg # this is not
Pycharm (v2021.2) 检查将属性 arg2
突出显示为未解析的属性。
def test_type_hint_example():
obj = Outer(Inner(1))
assert obj.inner.arg == 1
assert obj.inner.arg2 == 1 # inspection highlights arg2 as "unresolved attribute"
是否可以输入提示以便检查识别 arg2 是什么?
通常我会倾向于更改 Outer.inner
的类型提示,但在这种情况下那将是一个错误。 inner
可以是任何符合 InnerProto
.
我的第二个想法是覆盖实例属性的类型提示。这种类型的技巧对非属性对象有效,但在这种情况下会导致不同的检查错误:“Non-self attribute could not be type hinted”
def test_option1():
obj = Outer(Inner(1))
obj.inner: Inner # fixes inspection for arg2, but "Non-self attribute could not be type hinted" occurs
assert obj.inner.arg == 1
assert obj.inner.arg2 == 1
还有哪些其他选择?
我认为这里的问题是代码不是类型安全的。
您的 Outer.__init__
函数是:
class Outer:
def __init__(self, inner: InnerProto):
self.inner = inner
# <-- snip -->
您用 InnerProto
注释了 inner
参数。这意味着 Outer.inner
属性可以是 任何 类型,只要该类型符合 InnerProto
协议。
根据您的说法,这是正确的类型提示:
Normally I would be inclined to alter the type hint of
Outer.inner
but in this case that would be a mistake.inner
can be ANY class that conforms toInnerProto
.
如果是这种情况,则静态类型检查器无法验证 Outer.inner
是否具有 InnerProto
中未指定的任何属性或方法。这就是类型检查器在您的 test_type_hint_example
函数中引发错误的原因:您已经告诉类型检查器 Outer.inner
可以是任何类型,只要该类型符合 InnerProto
,但是 InnerProto
没有说明 arg2
属性,而且并非所有 python 类型都具有 arg2
属性,因此您可能会得到 AttribiteError
当你访问 Outer.inner.arg2
.
如果您确定,在这个特定函数的上下文中,Outer.inner
将是Inner
,因此可以保证具有 arg2
属性——尽管事实上在大多数情况下,Outer.inner
“可以是任何符合 InnerProto
的 class” — 然后你可以像这样使用 typing.cast
:
from typing import cast
def test_type_hint():
obj = Outer(Inner(1))
inner = cast(Inner, obj.inner)
assert inner.arg == 1
assert inner.arg2 == 1
然而,实际上,如果您 确定 Outer.inner
可以保证具有 arg2
属性,则很可能表明您确实,实际上, Outer.inner
的类型提示错误(如果不查看更多代码库,很难告诉您正确的类型提示是什么)。以我上面刚刚演示的方式使用 typing.cast
通常只能作为最后的手段使用——它更像是一种逃避类型检查的方法,从长远来看这对你没有帮助 运行如果您的代码不是类型安全的。