typing module documentation表示下面的两段代码是等效的.

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int

from collections import namedtuple

Employee = namedtuple('Employee', ['name', 'id'])

它们是完全一样的吗?如果不是,这两种实现之间的区别是什么?

推荐答案

子类typing.NamedTuple生成的类型相当于collections.namedtuple,但添加了__annotations___field_types_field_defaults个属性.出于所有实际目的,生成的代码的行为都是相同的,因为Python中目前没有任何东西作用于那些与类型相关的属性(不过,您的IDE可能会使用它们).

作为开发人员,将typing模块用于namedtuples可以提供更自然的声明性界面:

  • 您可以轻松地为字段指定默认值(102: in Python 3.7, 101 100 so this is no longer an advantage)
  • 您不需要重复两次类型名称("Employee")
  • 您可以直接自定义类型(例如添加docstring或某些方法)

和以前一样,您的类将是tuple的子类,而实例将像往常一样是tuple的实例.有趣的是,您的类将不是NamedTuple的子类.如果您想知道原因,请继续阅读以了解有关实施细节的更多信息.

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int

Behaviour in Python <= 3.8

>>> issubclass(Employee, NamedTuple)
False
>>> isinstance(Employee(name='guido', id=1), NamedTuple)
False

typing.NamedTuple是一个类,它使用metaclasses和自定义__new__来处理注释,然后使用delegates to collections.namedtuple, anyway, to build and return the type.正如您可能已经从小写名称约定中猜到的,collections.namedtuple不是一个类型/类——它是一个工厂函数.它的工作原理是构建一个Python源代码字符串,然后在此字符串上调用exec.generated constructor is plucked out of a namespaceincluded in a 3-argument invocation of the metaclass type用于构建并返回您的类.这就解释了上述奇怪的继承破坏,NamedTuple使用一个元类来实例化类对象.

Behaviour in Python >= 3.9

typing.NamedTupleclass变为def.

>>> issubclass(Employee, NamedTuple)
TypeError: issubclass() arg 2 must be a class or tuple of classes
>>> isinstance(Employee(name="guido", id=1), NamedTuple)
TypeError: isinstance() arg 2 must be a type or tuple of types

使用NamedTuple的多重继承现在是不允许的(它最初没有正常工作).

有关更改,请参见bpo40185/GH-19371.

Python-3.x相关问答推荐

在 Django 中执行 JSONRenderer.render(serialized_student_data.data) 时遇到问题

pymongo 失败并出现错误“未定义”

BeautifulSoup 和 pd.read_html - 如何将链接保存到最终数据框中的单独列中?

排队多个子进程

Python选择将整数除法向负无穷大的数学原因是什么?

根据条件过滤元组列表

所有 Python dunder 方法的列表 - 您需要实现哪些方法才能正确代理对象?

IronPython 3 支持?

在 macbook pro M1 上安装 Tensorflow 时出现“zsh:非法硬件指令 python”

理解 Python 交换:为什么 a, b = b, a 并不总是等价于 b, a = a, b?

如何摆脱密码学构建错误?

为什么从原始列表中弹出会使 reversed(original_list) 为空?

当字符串周围的引号不匹配时,为什么 Python 不给出任何错误?

如何从字典中打印特定键值?

正则表达式找到一对相邻的数字,它们周围有不同的数字

全局捕获快速 api 中的“异常”

从 __future__ 导入注释

基本 Flask 应用程序未运行(TypeError:模块中缺少必填字段“type_ignores”)

cv2 python 没有 imread 成员

如何解决“No module named 'frontend'”错误消息?