NamedTuple
是一个typing的超类,用于从collections.namedtuple
工厂生成的结构化对象;TypedDict
是Mypy尝试定义使用固定模式字典时出现的键和相应值的类型的。如果你只考虑“我有一组固定的键,应该映射到一组固定的类型化值”,它们是相似的。但是,它们的实现和约束非常不同。袋子和盒子相似吗?也许。也可能不是。这取决于你的观点和你想如何使用它们。倒杯酒,让讨论开始吧!NamedTuple
现在是Python的正式部分。from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
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})
还有一种基于类的类型构造函数可用:
class Movie(TypedDict):
name: str
year: int
ConnectionOptions = Dict[str, str]
TypedDict
语法?因为还有基于类的语法,使它们在语法上看起来与 NamedTuple
完全相同。 - Christoph有一些细微的差异。请注意,这些容器并不是永远存在的:
如果可能的话,我会选择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)
我认为它更加直观易懂,同时也让mypy有更多的检查可能性:
class UserTuple(NamedTuple):
name: str
gender: Gender
# vs
UserTuple = namedtuple("UserTuple", ["name", "gender"])
如果我不需要可变的东西,我更喜欢它们不可变。这样我就可以防止意外的副作用。
在Python 3.8+中,TypedDict
是一个简单的类型化命名空间,在运行时等效于普通的字典。
而
NamedTuple
是“元组子类”。请注意,命名元组实例没有每个实例字典,因此它们很轻便,不需要比常规元组更多的内存。
(来自这里)
命名元组子类也可以有文档字符串和方法。
用我的话来说,NamedTuple
更像自定义对象,TypedDict
则更像类型化字典。
从这些描述中可以看出,我预期NamedTuple
在运行时和内存方面具有一些(小)优势。但是,如果您正在使用期望字典的API,TypedDict
可能更可取,因为它是字典(尽管您也可以通过其_asdict()
方法从NamedTuple
创建字典)。
以下内容来自Steven F. Lott和Dusty Phillips的优秀书籍"Python面向对象编程":
- 在很多情况下,
dataclasses
提供了许多有用的功能,而且写的代码更少。它们可以是不可变的或可变的,给我们提供了广泛的选择。- 对于数据不可变的情况,
NamedTuple
比被冻结的dataclass
稍微高效一些,大约高出5%-不多。在这里平衡的关键是昂贵的属性计算。虽然NamedTuple
可以具有属性,但如果计算非常昂贵并且结果经常使用,则事先计算它可能有所帮助,这是NamedTuple
不擅长的。在极少数需要预先计算属性值的情况下,查看dataclasses
和它们的__post_init__()
方法的文档作为更好的选择。- 当键的完整集合事先未知时,字典是理想的。当我们开始设计时,我们可能会使用字典进行一次性原型或概念验证。当我们尝试编写单元测试和类型提示时,我们可能需要增加正式性。在某些情况下,可能已知可能键的域,并且
TypedDict
类型提示作为表征有效键和值类型的方法是有意义的。
namedtuple
和dict
看起来相似吗? - Azat IbrakovNamedTuple
和TypedDict
之间的区别,首先应该理解namedtuple
和dict
之间的区别。 - Jeyekomon