Python / mypy中NamedTuple和TypedDict的主要区别是什么

Chr*_*oph 4 python dictionary types namedtuple mypy

在我看来,这NamedTupleTypedDict相当相似,Python开发人员自己承认。

关于PEP,我宁愿添加有关NamedTuple和TypedDict的共同部分,它们非常相似,后者已经在结构上起作用。你怎么看? 资源

但是后来圭多对此不太确定。

我不确定NamedTuple和TypedDict是否真的一样(除非它们都试图在静态类型的世界中处理过时的模式)。

资源

因此,这是我懒惰的尝试,目的是使其他人在官方文档似乎缺乏的情况下进行清晰的比较。

Jon*_*ice 17

Python及其社区正在努力解决“结构”问题:如何最好地将相关值分组到复合数据对象中,从而可以逻辑/轻松地访问组件(通常按名称)。有许多竞争方法:

  • collections.namedtuple 实例
  • 字典(具有一组固定/已知的键)
  • 属性可访问的字典(如stuf
  • ATTRS
  • PEP 557 数据类
  • 每种结构类型均手工制作的普通旧定制对象
  • 每个位置/位置都具有类似tuplelist含暗含含义的序列(陈旧但极为常见)
  • 等等

“应该有一种(最好只有一种)明显的方式来做到这一点”。

typing像整个Python社区一样,库和Mypy都在同时努力解决如何更有效地定义类型/模式(包括复合对象)的问题。您链接到的讨论是该工作的一部分,并试图找到前进的方向。

NamedTuplecollections.namedtuple工厂产生的结构化对象的键入超类;TypedDictMypy尝试定义使用固定模式字典时出现的键和相应的值类型。如果您只是在考虑“我有一组固定的键应该映射到一组固定的类型值”,它们是相似的。但是最终的实现方式和约束条件却大不相同。袋子和盒子相似吗?也许。也许不吧。取决于您的观点和使用方式。倒酒,让讨论开始!

NamedTuple顺便说一句,现在已成为Python的正式组成部分。

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int
Run Code Online (Sandbox Code Playgroud)

TypedDict作为Mypy的一项实验性功能开始了生活,它可以将打字纠缠于异类,面向结构的字典使用。但是,从python 3.8开始,它已被标准库采用。

try:
    from typing import TypedDict  # >=3.8
except ImportError:
    from mypy_extensions import TypedDict  # <=3.7

Movie = TypedDict('Movie', {'name': str, 'year': int})
Run Code Online (Sandbox Code Playgroud)

也可以使用基于类的类型构造函数:

class Movie(TypedDict):
    name: str
    year: int
Run Code Online (Sandbox Code Playgroud)

尽管存在分歧,两者NamedTupleTypedDict锁定特定的键被使用,并且该类型的对应于每个键的值。因此,他们的目标基本上是相同的目标:对复合/结构类型使用有用的键入机制。

Python的标准typing.Dict侧重于更均匀的并行映射,定义键/值类型,而不是键本身。因此,在定义碰巧存储在字典中的复合对象时,它并不是很有用。

ConnectionOptions = Dict[str, str] 
Run Code Online (Sandbox Code Playgroud)

  • 我认为主要讨论了相似之处,但没有讨论差异。 (4认同)
  • 更新:从 Python 3.8 开始,TypedDict 现已成为标准库的一部分!https://docs.python.org/3/library/typing.html#typing.TypedDict (2认同)

Mar*_*oma 9

有一些细微的差别。请注意,这些容器并没有永远存在:

NamedTuple如果可能的话,如果我想冻结这些值,我会去。否则我会使用数据类。

from dataclasses import dataclass
from typing import NamedTuple, TypedDict
from enum import Enum


class Gender(Enum):
    MALE = "male"
    FEMALE = "female"


## Class definition: Almost the same
@dataclass
class UserDataC:
    name: str
    gender: Gender


class UserTuple(NamedTuple):
    name: str
    gender: Gender


class UserNDict(TypedDict):
    name: str
    gender: Gender


## Object Creation: Looks the same
anna_datac = UserDataC(name="Anna", gender=Gender.FEMALE)
anna_tuple = UserTuple(name="Anna", gender=Gender.FEMALE)
anna_ndict = UserNDict(name="Anna", gender=Gender.FEMALE)

## Mutable values vs frozen values
anna_datac.gender = Gender.MALE
# anna_tuple.gender = Gender.MALE  # AttributeError: can't set attribute
anna_ndict["gender"] = Gender.MALE
# AttributeError: 'dict' object has no attribute 'gender'
# anna_ndict.gender = Gender.MALE

## New attribute
# Note that you can add new attributes like this.
# Python will not complain. But mypy will.
anna_datac.password = "secret"  # Dataclasses are extensible
# anna_tuple.password = "secret"  # AttributeError - named tuples not
# anna_ndict.password = "secret"  # AttributeError - TypedDict not
anna_ndict["password"] = "secret"

## isinstance
assert isinstance(anna_tuple, tuple)
assert isinstance(anna_ndict, dict)
Run Code Online (Sandbox Code Playgroud)

为什么我更喜欢 NamedTuple 而不是 namedtuple

我认为写和读更直观。另外,您可以为 mypy 提供更多检查的可能性:

class UserTuple(NamedTuple):
    name: str
    gender: Gender

# vs

UserTuple = namedtuple("UserTuple", ["name", "gender"])
Run Code Online (Sandbox Code Playgroud)

为什么我更喜欢元组而不是字典

如果我不需要事物可变,我喜欢它们不是可变的。这样我可以防止意外的副作用


Mar*_*ark 6

A TypedDict(在 3.8+ 中)是

一个简单的类型命名空间。在运行时,它相当于一个普通的 dict。

而 aNamedTuple是“元组子类”。注意

命名元组实例没有每个实例的字典,因此它们是轻量级的,不需要比常规元组更多的内存。

和(从这里

NamedTuple 子类也可以有文档字符串和方法

用我自己的话来说,aNamedTuple更像是一个自定义对象,而 aTypedDict更像是一个类型化的字典。

我没有检查过,但是从这些描述中,我希望NamedTuplesTypedDicts有一些(小的)运行时和内存优势。

但是,例如,如果您正在使用需要 a 的 API,则dictaTypedDict可能更可取,因为它是 a dict(尽管您也可以通过其方法dict从 a创建 a )。NamedTuple_asdict()


Vla*_*den 5

来自Steven F. Lott 和 Dusty Phillips 所著的优秀著作《Python 面向对象编程》 :

\n
\n
    \n
  1. 对于很多情况,dataclasses可以通过更少的代码编写来提供许多有用的功能。它们可以是不可变的,也可以是可变的,为我们提供了广泛的\xc2\xa0选项。
  2. \n
  3. 对于数据不可变的情况,a 的NamedTuple效率可能比 freeze 的效率高dataclass大约 5% \xe2\x80\x93 不多。这里打破平衡的是昂贵的属性计算。虽然 aNamedTuple可以具有属性,但如果计算成本非常高并且结果被频繁使用,它可以帮助提前计算它,这NamedTuple是 a 不擅长的。查看文档dataclasses及其__post_init__()在极少数情况下,提前计算属性值很有帮助,请
  4. \n
  5. 当事先不知道完整的键集时,字典是理想的选择。当我们开始设计时,我们可能有一次性原型或使用字典的概念证明。当我们尝试编写单元测试和类型提示时,我们可能需要加强形式。在某些情况下,可能的键的域是已知的,并且TypedDict类型提示作为表征有效键和值类型的一种方式是有意义的。
  6. \n
\n
\n