如何测试 python 类型协议是另一个协议的子类?

Dar*_*ber 5 python inheritance protocols typing

问题的明显解决方案是使用issubclass,但这会引发TypeError(使用 Python 3.6.7),例如

>>> from typing_extensions import Protocol
>>> class ProtoSubclass(Protocol):
...     pass
... 
>>> issubclass(ProtoSubclass, Protocol)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/conda/envs/airflow/lib/python3.6/site-packages/typing_extensions.py", line 1265, in __subclasscheck__
    raise TypeError("Instance and class checks can only be used with"
TypeError: Instance and class checks can only be used with @runtime protocols
>>> from typing_extensions import runtime
>>> @runtime
... class ProtoSubclass(Protocol):
...     pass
... 
>>> issubclass(ProtoSubclass, Protocol)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/conda/envs/airflow/lib/python3.6/site-packages/typing_extensions.py", line 1265, in __subclasscheck__
    raise TypeError("Instance and class checks can only be used with"
TypeError: Instance and class checks can only be used with @runtime protocols
Run Code Online (Sandbox Code Playgroud)

Nun*_*dré 12

所选答案虽然没有错误,但并没有反映 的实际使用Protocol,它提供了结构子类型。Python 3 始终可以使用名义子类型。

from typing import Protocol, runtime_checkable

@runtime_checkable
class Closable(Protocol):
    def close(self):
        ...

class AnyClass:
    def close(self):
        ...

issubclass(AnyClass, Closable)
#> True
Run Code Online (Sandbox Code Playgroud)

此外,runtime_checkable仅在基类中需要,即使正在检查的类是Protocol子类。

class ExtendedProtocol(Closable, Protocol):
    ...

class AnotherProtocol(Protocol):
    def close(self):
        ...

class NotAProtocol(Closable):
    # just inherits the protocol's default implementation
    ...

issubclass(ExtendedProtocol, Closable)
#> True
issubclass(AnotherProtocol, Closable)
#> True
issubclass(NotAProtocol, Closable)
#> True
Run Code Online (Sandbox Code Playgroud)


Dar*_*ber 5

有关 python 主题的更多信息Protocols,请参阅

在Python 3.6.7中,解决这个问题的一种方法是使用@runtime_checkable装饰器:

>>> from typing_extensions import Protocol
>>> from typing_extensions import runtime_checkable

>>> @runtime_checkable
... class CustomProtocol(Protocol):
...     def custom(self):
...         ...
... 

>>> @runtime_checkable
... class ExtendedCustomProtocol(CustomProtocol, Protocol):
...     def extended(self):
...         ...
... 

>>> issubclass(ExtendedCustomProtocol, CustomProtocol)
True
Run Code Online (Sandbox Code Playgroud)