Python协议:无法理解“类对象与协议”

cgh8pdjw  于 2023-02-11  发布在  Python
关注(0)|答案(1)|浏览(142)

我正在阅读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
有人能通过扩展这个概念来解释一下吗?这样我就能理解了。

bq3bfh9z

bq3bfh9z1#

在问题注解中讨论了一点并检查了a pull request addressing the example of the question之后,我现在可以理解为什么这个例子是正确的,以及我的推理哪里出错了。

典型案例:根据协议检查示例

让我们稍微扩展一下示例,考虑检查C的示例是ProtoA还是ProtoB的实现的更常见情况:

c: ProtoA = C()  # OK
c: ProtoB = C()  # Type check error, signature don't match!

因此,很明显,正如预期的那样,C的一个示例就是ProtoA的一个实现,因为ProtoA的承诺是它的任何实现都有一个可以被称为c.meth(2)的方法meth(在本例中,2可以是任何其他整数),我可以清楚地做到:

c.meth(2)  # This is correct according to the signature/type hints.

给定病例:根据协议检查类

那么,在这个例子中发生了什么?,发生的是C有一个方法meth,但是它没有被定义为类方法,所以,C.meth有一个和c.meth不同的签名,事实上,C.meth有一个由ProtoB承诺的签名,而不是由ProtoA承诺的,因为要直接从类中使用C.meth,我需要传递一个参数来满足self,它具有隐式类型Any

# This...
c = C()
c.meth(2)
# ...is equivalent to this.
c = C()
C.meth(c, 2)

# But the promise is fulfilled with anything as first argument
# because there is no explicit type hint for `self` and thus it is
# implicityly typed as `Any`.
C.meth('anything is fine here', 2)  # this is a correct call*

# *although it might result in an error depending on the implementation 
# if the `self` argument had runtime requirements not expressed in the 
# type hint.

这就是原因,它毕竟有一个简单的解释。

相关问题