Python 自定义鸭子类型的类型注释
Python type annotation for custom duck type
Python 的 typing
模块定义了许多鸭子类型,例如 typing.SupportsAbs
表示任何实现 __abs__
特殊方法的类型。
是否可以定义自定义鸭子类型,以便我可以将它们用作有效的类型注释?
例如,我希望能够注释一个参数应该是 threading.Lock
的鸭子类型等价物,即任何实现 acquire
和 [=16= 的对象] 方法。理想情况下,我可以将这样的参数注释为 SupportsAcquireAndRequire
或 DuckLock
,而不是 object
.
可以定义一个abstract base class (ABC)来指定接口:
from abc import ABCMeta, abstractmethod
class SupportsAcquireAndRequire(metaclass=ABCMeta):
@abstractmethod
def acquire(self):
pass
@abstractmethod
def release(self):
pass
@classmethod
def __subclasshook__(cls, C):
for method in ('release', 'acquire'):
for B in C.__mro__:
if method in B.__dict__:
if B.__dict__[method] is None:
return NotImplemented
break
else:
return NotImplemented
return True
这基本上就是协议(如 typing.SupportsAbs
)的实现方式,尽管没有直接使用 ABCMeta
。
通过给 ABC __subclasshook__
method, you can use it in isinstance()
and issubclass()
tests, which is more than good enough for tools like mypy
:
>>> from threading import Lock
>>> isinstance(Lock(), SupportsAcquireAndRequire)
True
typing
已更新以支持像这样的用例 - 您可以为此使用 typing.Protocol
。
from typing import Protocol, runtime_checkable
@runtime_checkable
class LockLike(Protocol):
def acquire(self) -> None:
...
def release(self) -> None:
...
如果您想像 Martijn 的回答那样使用 isinstance
,则需要 @runtimecheckable
。
>>> from threading import Lock
>>> isinstance(Lock(), RuntimeCheckable)
True
Python 的 typing
模块定义了许多鸭子类型,例如 typing.SupportsAbs
表示任何实现 __abs__
特殊方法的类型。
是否可以定义自定义鸭子类型,以便我可以将它们用作有效的类型注释?
例如,我希望能够注释一个参数应该是 threading.Lock
的鸭子类型等价物,即任何实现 acquire
和 [=16= 的对象] 方法。理想情况下,我可以将这样的参数注释为 SupportsAcquireAndRequire
或 DuckLock
,而不是 object
.
可以定义一个abstract base class (ABC)来指定接口:
from abc import ABCMeta, abstractmethod
class SupportsAcquireAndRequire(metaclass=ABCMeta):
@abstractmethod
def acquire(self):
pass
@abstractmethod
def release(self):
pass
@classmethod
def __subclasshook__(cls, C):
for method in ('release', 'acquire'):
for B in C.__mro__:
if method in B.__dict__:
if B.__dict__[method] is None:
return NotImplemented
break
else:
return NotImplemented
return True
这基本上就是协议(如 typing.SupportsAbs
)的实现方式,尽管没有直接使用 ABCMeta
。
通过给 ABC __subclasshook__
method, you can use it in isinstance()
and issubclass()
tests, which is more than good enough for tools like mypy
:
>>> from threading import Lock
>>> isinstance(Lock(), SupportsAcquireAndRequire)
True
typing
已更新以支持像这样的用例 - 您可以为此使用 typing.Protocol
。
from typing import Protocol, runtime_checkable
@runtime_checkable
class LockLike(Protocol):
def acquire(self) -> None:
...
def release(self) -> None:
...
如果您想像 Martijn 的回答那样使用 isinstance
,则需要 @runtimecheckable
。
>>> from threading import Lock
>>> isinstance(Lock(), RuntimeCheckable)
True