Python的typing模块定义了许多鸭子类型(duck typing),例如typing.SupportsAbs来表示实现__abs__特殊方法的任何类型。

是否可以通过某种方式定义自定义鸭子类型(duck typing),以便可以将它们用作有效的类型注释?

例如,我希望能够注释一个参数应该是threading.Lock的鸭子类型(duck typing)等效项,即,任何实现acquirerelease方法的对象。理想情况下,我可以注释诸如SupportsAcquireAndRequireDuckLock这样的参数,而不是object

最佳答案

您可以定义一个abstract base class (ABC)来指定接口(interface):

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

基本上,这是协议(protocol)(如typing.SupportsAbs)的实现方式,尽管不直接使用ABCMeta

通过给ABC一个 __subclasshook__ method,您可以在isinstance()issubclass()测试中使用它,对于 mypy 这样的工具来说已经足够了:
>>> from threading import Lock
>>> isinstance(Lock(), SupportsAcquireAndRequire)
True

09-17 23:08