typing
module documentation说下面的两个代码片段是等价的。
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
和
from collections import namedtuple
Employee = namedtuple('Employee', ['name', 'id'])
它们是完全相同的东西吗?或者,如果不是,两个实现之间的区别是什么?
发布于 2018-06-09 03:22:46
通过子类化typing.NamedTuple
生成的类型等同于collections.namedtuple
,但添加了__annotations__
、_field_types
和_field_defaults
属性。出于所有实际目的,生成的代码的行为都是一样的,因为Python中目前没有任何东西作用于那些与类型相关的属性(尽管您的IDE可能会使用它们)。
作为开发人员,对命名元组使用typing
模块可以提供更自然的声明性接口:
collections.namedtuple
使其不再是advantage)与以前一样,您的类将成为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
, anyway, 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
。这解释了上面看到的奇怪的继承中断,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
的多重继承(它从一开始就不能正常工作)。
https://stackoverflow.com/questions/50766461
复制相似问题