Mat*_*bin 22 python type-hinting python-3.x
假设我有两个类Foo1
并且Foo2
实现了一个方法bar()
:
Foo1
,bar()
是一个正则方法Foo2
,bar()
是一个@classmethod
class Foo1:
def bar(self) -> None:
print("foo1.bar")
class Foo2:
@classmethod
def bar(cls) -> None:
print("Foo2.bar")
Run Code Online (Sandbox Code Playgroud)
现在假设我有一个函数,它接受“任何有bar()
方法的东西”列表并调用它:
def foreach_foo_call_bar(foos):
for foo in foos:
foo.bar()
Run Code Online (Sandbox Code Playgroud)
在运行时调用此函数工作正常:
foreach_foo_call_bar([Foo1(), Foo2])
Run Code Online (Sandbox Code Playgroud)
因为两者都有Foo1()
并且Foo2
有一个bar()
方法。
但是,如何正确地将类型提示添加到foreach_foo_call_bar()
?
我尝试创建一个名为的PEP544 :Protocol
SupportsBar
class SupportsBar(Protocol):
def bar(self) -> None:
pass
Run Code Online (Sandbox Code Playgroud)
并像这样注释:
def foreach_foo_call_bar(foos: Iterable[SupportsBar]):
...
Run Code Online (Sandbox Code Playgroud)
但是 mypy 说:
List item 1 has incompatible type "Type[Foo2]"; expected "SupportsBar"
Run Code Online (Sandbox Code Playgroud)
知道如何正确注释吗?
问题似乎Protocol
是专门检查是否 支持实例方法,而不仅仅是存在正确名称的属性。在 的情况下Foo2
,这意味着元类需要一个名为 的实例方法bar
;以下似乎按预期行为和类型检查。
# Define a metaclass that provides an instance method bar for its instances.
# A metaclass instance method is almost equivalent to a class method.
class Barrable(type):
def bar(cls) -> None:
print(cls.__name__ + ".bar")
class Foo1:
def bar(self) -> None:
print("foo1.bar")
class Foo2(metaclass=Barrable):
pass
class SupportsBar(Protocol):
def bar(self) -> None:
pass
def foreach_foo_call_bar(foos: Iterable[SupportsBar]):
for foo in foos:
foo.bar()
Run Code Online (Sandbox Code Playgroud)
我不会声称将类方法转换为元类实例方法是一个很好的解决方法(实际上,它对静态方法没有任何作用),但它指出这是Protocol
它不处理任意属性的基本限制。
在列表中的第二项foos
,Foo2
是一个类不是一个实例如Foo1()
。这需要通过环绕来指定Type
:
def foreach_foo_call_bar(
foos: Iterable[Union[SupportsBar,
Type[SupportsBar]]]):
# ...
Run Code Online (Sandbox Code Playgroud)
您也可以在不使用 a 的情况下执行此操作Protocol
:
def foreach_foo_call_bar(
foos: Iterable[Union[Foo1,
Type[Foo2]]]):
# ...
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
599 次 |
最近记录: |