【问题标题】:What's the difference between namedtuple and NamedTuple?namedtuple 和 NamedTuple 有什么区别?
【发布时间】:2018-11-18 20:35:59
【问题描述】:

typing module documentation 表示下面两个代码 sn-ps 是等价的。

from typing import NamedTuple

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

from collections import namedtuple

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

它们是完全相同的东西吗?如果不是,这两种实现之间有什么区别?

【问题讨论】:

    标签: python python-3.x


    【解决方案1】:

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

    作为开发人员,为您的命名元组使用typing 模块可以实现更自然的声明式接口:

    • 您可以轻松地为字段指定默认值(编辑:在 Python 3.7 中,collections.namedtuplegot a new defaults keyword 所以这不再是优势
    • 您无需重复两次类型名称(“Employee”)
    • 您可以直接自定义类型(例如添加文档字符串或某些方法)

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

    from typing import NamedTuple
    
    class Employee(NamedTuple):
        name: str
        id: int
    

    Python 中的行为
    >>> 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 源代码,然后在该字符串上调用 execgenerated constructor is plucked out of a namespaceincluded in a 3-argument invocation of the metaclass type 用于构建和返回您的课程。这解释了上面看到的奇怪的继承中断,NamedTuple 使用元类来使用不同的元类来实例化类对象。

    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 了解更改。

    【讨论】:

    • 而且因为它是一个类,你也可以传递它的默认值,我认为你不能从namedtuple的集合中做到这一点。
    • @dfundako 通过对生成的类型进行子类化,collections.namedtuple 是可能的。但是typing.NamedTuple 允许更简单的界面。
    猜你喜欢
    • 2019-10-18
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 2016-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多