我正在阅读PEP 544,特别是类对象与协议的部分,我不能理解那里给出的最后一个例子,我将复制粘贴在这里:
如果访问类对象上的所有成员导致类型与协议成员兼容,则类对象被视为协议的实现。例如:
from typing import Any, Protocol
class ProtoA(Protocol):
def meth(self, x: int) -> int: ...
class ProtoB(Protocol):
def meth(self, obj: Any, x: int) -> int: ...
class C:
def meth(self, x: int) -> int: ...
a: ProtoA = C # Type check error, signatures don't match!
b: ProtoB = C # OK
我可以得到PEP的其余部分,但是这个例子对我来说似乎是违反直觉的,我认为类C
实现方法meth
时使用了与ProtoA
相同的签名,那么为什么a: ProtoA = C
行中会有错误呢?
为什么b: ProtoB = C
是正确的?C.meth
的签名不同于ProtoB.meth
的签名(后者包含一个额外的参数obj: Any
。
有人能通过扩展这个概念来解释一下吗?这样我就能理解了。
1条答案
按热度按时间bq3bfh9z1#
在问题注解中讨论了一点并检查了a pull request addressing the example of the question之后,我现在可以理解为什么这个例子是正确的,以及我的推理哪里出错了。
典型案例:根据协议检查示例
让我们稍微扩展一下示例,考虑检查
C
的示例是ProtoA
还是ProtoB
的实现的更常见情况:因此,很明显,正如预期的那样,
C
的一个示例就是ProtoA
的一个实现,因为ProtoA
的承诺是它的任何实现都有一个可以被称为c.meth(2)
的方法meth
(在本例中,2
可以是任何其他整数),我可以清楚地做到:给定病例:根据协议检查类
那么,在这个例子中发生了什么?,发生的是
C
有一个方法meth
,但是它没有被定义为类方法,所以,C.meth
有一个和c.meth
不同的签名,事实上,C.meth
有一个由ProtoB
承诺的签名,而不是由ProtoA
承诺的,因为要直接从类中使用C.meth
,我需要传递一个参数来满足self
,它具有隐式类型Any
:这就是原因,它毕竟有一个简单的解释。