蟒蛇的PEP 544 https://www.python.org/dev/peps/pep-0544/介绍typing.Protocol
用于结构子类型,又名“静态鸭子类型”。
在本 PEP 的部分中合并和扩展协议 https://www.python.org/dev/peps/pep-0544/#merging-and-extending-protocols,据说
总的理念是协议大多像常规的 ABC,
但静态类型检查器会专门处理它们。
因此,人们期望从子类继承typing.Protocol
与人们期望从子类继承的方式大致相同abc.ABC
:
from abc import ABC
from typing import Protocol
class AbstractBase(ABC):
def method(self):
print("AbstractBase.method called")
class Concrete1(AbstractBase):
...
c1 = Concrete1()
c1.method() # prints "AbstractBase.method called"
class ProtocolBase(Protocol):
def method(self):
print("ProtocolBase.method called")
class Concrete2(ProtocolBase):
...
c2 = Concrete2()
c2.method() # prints "ProtocolBase.method called"
正如预期的那样,具体子类Concrete1
and Concrete2
继承method
来自各自的超类。此行为记录在明确声明实施 https://www.python.org/dev/peps/pep-0544/#explicitly-declaring-implementationPEP 部分:
显式声明某个类实现给定的
协议,它可以用作常规基类。在这种情况下是一个类
可以使用协议成员的默认实现。
...
请注意,显式和隐式之间几乎没有区别
子类型,显式子类化的主要好处是获得一些
协议方法“免费”。
然而,当协议类实现__init__
方法,__init__
is not由协议类的显式子类继承。这与子类形成对比ABC
类,其中do继承__init__
method:
from abc import ABC
from typing import Protocol
class AbstractBase(ABC):
def __init__(self):
print("AbstractBase.__init__ called")
class Concrete1(AbstractBase):
...
c1 = Concrete1() # prints "AbstractBase.__init__ called"
class ProtocolBase(Protocol):
def __init__(self):
print("ProtocolBase.__init__ called")
class Concrete2(ProtocolBase):
...
c2 = Concrete2() # NOTHING GETS PRINTED
我们看到,Concrete1
继承__init__
from AbstractBase
, but Concrete2
不继承__init__
from ProtocolBase
。这与前面的示例相反,其中Concrete1
and Concrete2
两者都继承method
来自各自的超类。
我的问题是:
- 没有的理由是什么
__init__
由协议类的显式子类型继承?是否存在某种类型理论原因导致协议类无法提供__init__
方法“免费”?
- 有没有关于这种差异的文档?或者这是一个错误?