我尝试了明显的方法来检查我的协议:
from typing import Any, Protocol, runtime_checkable
@runtime_checkable
class SupportsComparison(Protocol):
def __eq__(self, other: Any) -> bool:
...
issubclass(int, SupportsComparison)
不幸的是,
issubclass()
调用以异常结束(Ubuntu 22.04 中的 Python 3.10.6):
$ python3.10 protocol_test.py
Traceback (most recent call last):
File "protocol_test.py", line 8, in <module>
issubclass(object, SupportsComparison)
File "/usr/lib/python3.10/abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
File "/usr/lib/python3.10/typing.py", line 1570, in _proto_hook
raise TypeError("Protocols with non-method members"
TypeError: Protocols with non-method members don't support issubclass()
如您所见,我没有向
SupportsComparison
添加任何非方法成员。这是标准库中的错误吗?
来自文档:
一个重写
并且没有定义__eq__()
的类 将其__hash__()
隐式设置为__hash__()
.None
因此,在您的情况下,您有隐式非方法成员
SupportsComparison.__hash__ = None
。您可以通过明确声明__hash__
来修复它:
from typing import Any, Protocol, runtime_checkable
@runtime_checkable
class SupportsComparison(Protocol):
def __eq__(self, other: Any) -> bool:
...
def __hash__(self) -> int:
...
issubclass(int, SupportsComparison)
您看到的错误消息与您已将非方法成员添加到 SupportsComparison 协议这一事实无关。相反,问题在于您在协议上使用了
@runtime_checkable
装饰器,这向 Python 表明可以在运行时检查协议的实例。但是,issubclass()
不支持具有非方法成员的协议,当它们被标记为@runtime_checkable
.
如果从协议定义中删除
@runtime_checkable
装饰器,issubclass()
调用应该按预期工作:
from typing import Any, Protocol
class SupportsComparison(Protocol):
def __eq__(self, other: Any) -> bool:
pass
print(issubclass(int, SupportsComparison)) # Output: False
print(issubclass(str, SupportsComparison)) # Output: True
在这个例子中,我们删除了
@runtime_checkable
装饰器并定义了一个SupportsComparison协议,只有一个方法__eq__()
。然后我们调用 issubclass()
来检查 int 和 str 类型是否是 SupportsComparison
协议的子类。
如果你想检查一个给定的对象是否支持你的协议,你可以使用
isinstance()
函数而不是issubclass()
。这是一个例子:
def is_supports_comparison(obj: Any) -> bool:
return isinstance(obj, SupportsComparison)
print(is_supports_comparison(42)) # Output: False
print(is_supports_comparison("hello")) # Output: True
is_supports_comparison()
函数,该函数将一个对象作为参数,如果该对象支持SupportsComparison协议,则返回True。我们用一个 int 和一个 str 调用这个函数来测试它们是否支持该协议。如果您需要在您的协议中保留
@runtime_checkable
装饰器,您可以使用isinstance()
函数而不是issubclass()
来检查对象是否支持您的协议。 isinstance()
函数支持带有非方法成员的协议,当它们被标记为 @runtime_checkable
.
举个例子:
from typing import Any, Protocol, runtime_checkable
@runtime_checkable
class SupportsComparison(Protocol):
def __eq__(self, other: Any) -> bool:
pass
class MyClass:
pass
class MyOtherClass:
def __eq__(self, other: Any) -> bool:
return True
# Check if an object supports SupportsComparison protocol
obj1 = MyClass()
obj2 = MyOtherClass()
print(isinstance(obj1, SupportsComparison)) # Output: False
print(isinstance(obj2, SupportsComparison)) # Output: True
在这个例子中,我们定义了带有
SupportsComparison
装饰器和单一方法@runtime_checkable
的__eq__()
协议。我们还定义了两个类 MyClass
和 MyOtherClass
。只有MyOtherClass
实现了__eq__()
方法,所以支持SupportsComparison
协议。
要检查对象是否支持 SupportsComparison 协议,我们使用
isinstance()
函数并将对象作为第一个参数传递,将协议对象作为第二个参数传递。在此示例中,obj1
不支持该协议,而 obj2
支持。