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
命名元组的模块允许更自然的声明性接口(interface):
- 您可以轻松地为字段指定默认值(编辑:在 Python 3.7 中,
collections.namedtuple
got a newdefaults
keyword 所以这不再是优势) - 您无需重复两次类型名称(“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
是一个类,它使用 metaclasses和自定义 __new__
处理注释,然后它 delegates to collections.namedtuple
to build and return the type .正如您可能已经从小写的名称约定中猜到的那样,collections.namedtuple
不是类型/类 - 它是工厂函数。它的工作原理是构建一串 Python 源代码,然后调用 exec
在这个字符串上。 generated constructor is plucked out of a namespace和 included in a 3-argument invocation of the metaclass type
建立并返回你的类(class)。这解释了上面看到的奇怪的继承中断,NamedTuple
使用元类以便使用不同的元类来实例化类对象。
Python 中的行为 >= 3.9
typing.NamedTuple
从类型(class
)更改为函数(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
的多重继承现在是不允许的(它一开始就不能正常工作)。
关于python - namedtuple 和 NamedTuple 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50766461/