python - namedtuple 和 NamedTuple 有什么区别?
问题描述
typing
模块文档说下面的两个代码片段是等效的。
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
和
from collections import namedtuple
Employee = namedtuple('Employee', ['name', 'id'])
它们是完全相同的东西吗?如果不是,这两种实现之间有什么区别?
解决方案
子类化生成的类型typing.NamedTuple
等价于 a collections.namedtuple
,但添加了__annotations__
,_field_types
和_field_defaults
属性。出于所有实际目的,生成的代码将具有相同的行为,因为 Python 中目前没有任何内容对那些与键入相关的属性起作用(尽管您的 IDE 可能会使用它们)。
作为开发人员,typing
为您的命名元组使用该模块可以实现更自然的声明式接口:
- 您可以轻松地为字段指定默认值(编辑:在 Python 3.7 中,
collections.namedtuple
获得了一个新defaults
关键字,因此这不再是优势) - 您不需要重复类型名称两次(“Employee”)
- 您可以直接自定义类型(例如添加文档字符串或某些方法)
和以前一样,您的类将是 的子类tuple
,而实例将是tuple
照常的实例。有趣的是,您的类不会是NamedTuple
. 如果您想知道原因,请继续阅读以获取有关实施细节的更多信息。
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
Python <= 3.8 中的行为
>>> issubclass(Employee, NamedTuple)
False
>>> isinstance(Employee(name='guido', id=1), NamedTuple)
False
typing.NamedTuple
是一个类,它使用元类和自定义__new__
来处理注释,然后它委托给collections.namedtuple
,无论如何,构建和返回类型。正如您可能从小写的名称约定中猜到的那样,collections.namedtuple
它不是类型/类 - 它是一个工厂函数。它的工作原理是构建一串 Python 源代码,然后调用exec
这个字符串。生成的构造函数从命名空间中提取出来,并包含在元类的 3 参数调用中,type
以构建和返回您的类。这解释了上面看到的奇怪的继承破坏,NamedTuple
使用元类以使用不同的元类来实例化类对象。
Python 中的行为 >= 3.9
typing.NamedTuple
由 aclass
变为 a 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
(它一开始就不能正常工作)。
推荐阅读
- android - 使用 android 可访问性从 imageview 获取图像
- angular - 如何以角度进行服务器端 API 调用以绕过 CORS 错误
- android - 使用片段的谷歌地图
- azure-data-factory - 监控未显示所有管道运行
- python - 如何在 Python 中将 for 循环转换为带有工作 if 语句的嵌套 while 循环
- python - 密钥错误消息
- python - 使用 Python 更改目录,找不到目录错误
- powershell - 使用 PowerShell 在远程计算机上安装 MSI 文件
- javascript - 如何检查一个充满 Jquery 对象的数组的值
- php - Laravel 验证器正则表达式:以逗号分隔格式验证所有内容