type.Protocol 类 `__init__` 方法在显式子类型构造期间未调用

2024-04-11

蟒蛇的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来自各自的超类。

我的问题是:

  1. 没有的理由是什么__init__由协议类的显式子类型继承?是否存在某种类型理论原因导致协议类无法提供__init__方法“免费”?
  2. 有没有关于这种差异的文档?或者这是一个错误?

您不能直接实例化协议类。这是目前已实施 https://github.com/python/cpython/blob/v3.8.3/Lib/typing.py#L1113通过替换协议的__init__使用其唯一功能是强制执行此限制的方法:

def _no_init(self, *args, **kwargs):
    if type(self)._is_protocol:
        raise TypeError('Protocols cannot be instantiated')

...

class Protocol(Generic, metaclass=_ProtocolMeta):
    ...

    def __init_subclass__(cls, *args, **kwargs):
        ...
        cls.__init__ = _no_init

Your __init__不会执行,因为它不再存在了。

这非常奇怪,并且比乍一看更混乱 - 例如,它与多重继承的交互很差,中断super().__init__ chains.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

type.Protocol 类 `__init__` 方法在显式子类型构造期间未调用 的相关文章

  • Pygame 中可以改变精灵颜色吗?

    我正在使用 Pygame 在 Python 中制作一个游戏 其中在游戏开始前包括一个小型头像制作器 但不是创建一个包含 88 种不同发型和颜色组合的大精灵表 有没有一种方法可以让我只使用通用的 每个发型的 png 图像并在游戏中为其应用颜色
  • pyvenv-3.4 返回非零退出状态 1

    我在 Kubuntu 14 04 我想用 python3 4 创建一个 virtualenv 我之前在其他文件夹中使用过 python2 7 但是当我尝试时 pyvenv 3 4 venv 我有 Error Command home fmr
  • 无法在 VS Code 中导入

    我是 python 新手 一直在使用 VS code 现在我正在研究汤普森采样问题 需要 numpy 和 matplotlib 我已经导入了这两个库 但 VS code 给出了无法导入的错误 我知道我必须使用 PIP 进行安装 并且我已经看
  • 如何使用BeautifulSoup查找所有下一个链接

    我目前正在通过预设一个名为 number of pages 的变量来抓取特定网站的所有页面 预设此变量一直有效 直到添加了我不知道的新页面 例如 下面的代码适用于 3 个页面 但网站现在有 4 个页面 base url https secu
  • Python3.5 BeautifulSoup4从div中的'p'获取文本

    我试图从 div 类 caselawcontent searchable content 中提取所有文本 此代码仅打印 HTML 不打印网页中的文本 我缺少什么来获取文本 以下链接位于 finteredcasesdoc text 文件中 h
  • .NET 中有处理 Modbus 协议的好库吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有谁知道有一个好的 最好是开源的 库来处理 Modbus 协议 我看过一些图书馆 但我正在寻找一些人的
  • 导入错误 - 发生了什么?

    Python 导入 再次 我有这个文件结构 test start py from scripts import main scripts init py empty main py from import install install p
  • Pandas:如何根据另一个数据框的值对数据框上的列求和

    我是 Pandas 新手 我正在尝试做以下事情 我有一个名为的数据框comms包含articleID和commentScore列 等等 我有另一个名为arts带有列文章 ID 我需要创建arts一个名为文章评分 每篇文章必须具有articl
  • 为什么 enumerate、zip、range 类型不属于 types.GeneratorType?

    Python 3 引入了类似生成器的对象 在调用时返回range and zip 返回的对象就像一个生成器 可以迭代一次 但不能很好地 打印 就像enumerate 返回参数 然而 我很困惑地发现它们是不同的对象类型并且不属于types G
  • Selenium Python Firefox webdriver:无法修改配置文件

    我想在 Webdriver Firefox 实例上使用 新选项卡而不是窗口 选项 1 我创建了一个启用此选项的配置文件 但是当我使用该配置文件时 很多选项都可以 但不是这个 2 加载配置文件后 我尝试更改代码中的选项 但它不起作用 我的代码
  • 查找两个复杂字典之间的集合差异

    我有两个结构如下的字典 a dict1 a 1 2 3 4 b 1 2 5 6 b dict2 a 1 2 5 6 b 1 2 7 8 我需要找到字典中每个键之间的设置差异 即 dict1 a dict2 a 应该返回 3 4 任何想法都值
  • FastAPI/Pydantic 接受任意 post 请求正文吗?

    我想创建一个 FastAPI 端点 它只接受任意的 post 请求正文并返回它 如果我发送 foo bar 我想得到 foo bar 后退 但我也希望能够发送 foo1 bar1 foo2 bar2 并把它拿回来 我试过 from fast
  • 现在与出生日期之间的年、月、日、分钟差异

    import datetime birthday datetime datetime 1996 8 15 differnce datetime datetime now birthday This returns a timedelta o
  • “ModuleNotFoundError:我的 Docker 容器中没有名为 的模块”

    我正在尝试在 Docker 容器中运行 python 脚本 但我不知道为什么 python 找不到任何 python 模块 我认为它与 PYTHONPATH 环境变量有关 所以我尝试将其添加到 Dockerfile 中 如下所示 ENV P
  • 初始化 dask 分布式工作线程的状态

    我正在尝试做类似的事情 resource MyResource def fn x something dosemthing x resource return something client Client results client m
  • 表达式中的 Python 'in' 关键字与 for 循环中的比较 [重复]

    这个问题在这里已经有答案了 我明白什么是in运算符在此代码中执行的操作 some list 1 2 3 4 5 print 2 in some list 我也明白i将采用此代码中列表的每个值 for i in 1 2 3 4 5 print
  • 如何使用魔杖扭曲图像

    我正在尝试做同样的事情this https stackoverflow com questions 52090350 how to insert image in a mock up老问题但在python using wand 到目前为止我
  • While 在范围内循环用户输入

    我有一些代码 我想要求用户输入 1 100 之间的数字 如果他们在这些数字之间输入一个数字 它将打印 Size input 并打破循环 但是 如果他们在外部输入一个数字1 100 它将打印 大小 输入 并继续向他们重新询问一个数字 但我遇到
  • 如何在 Detectron2 中计算并集交集?

    我正在使用 Detectron2 进行对象检测 我已经注册了 pascalvoc 数据集并训练了一个检测模型 如何计算测试数据集的平均 IOU 我知道 detector2 有一个用于计算 IOU 的预定义函数 即 detectorron2
  • Django model.foreignKey 并返回 self.text 错误

    所以我正在 Django 中处理 model py 但遇到了 2 个 pylint 错误 我不明白为什么 这是 pylint 的问题还是我在代码中做错了什么 E1120 No value for argument on delete in

随机推荐