Chr*_*oph 4 python dictionary types namedtuple mypy
在我看来,这NamedTuple和TypedDict相当相似,Python开发人员自己承认。
关于PEP,我宁愿添加有关NamedTuple和TypedDict的共同部分,它们非常相似,后者已经在结构上起作用。你怎么看? 资源
但是后来圭多对此不太确定。
我不确定NamedTuple和TypedDict是否真的一样(除非它们都试图在静态类型的世界中处理过时的模式)。
因此,这是我懒惰的尝试,目的是使其他人在官方文档似乎缺乏的情况下进行清晰的比较。
Jon*_*ice 17
Python及其社区正在努力解决“结构”问题:如何最好地将相关值分组到复合数据对象中,从而可以逻辑/轻松地访问组件(通常按名称)。有许多竞争方法:
collections.namedtuple 实例tuple和list含暗含含义的序列(陈旧但极为常见)“应该有一种(最好只有一种)明显的方式来做到这一点”。
typing像整个Python社区一样,库和Mypy都在同时努力解决如何更有效地定义类型/模式(包括复合对象)的问题。您链接到的讨论是该工作的一部分,并试图找到前进的方向。
NamedTuple是collections.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)
尽管存在分歧,两者NamedTuple并TypedDict锁定特定的键被使用,并且该类型的对应于每个键的值。因此,他们的目标基本上是相同的目标:对复合/结构类型使用有用的键入机制。
Python的标准typing.Dict侧重于更均匀的并行映射,定义键/值类型,而不是键本身。因此,在定义碰巧存储在字典中的复合对象时,它并不是很有用。
ConnectionOptions = Dict[str, str]
Run Code Online (Sandbox Code Playgroud)
有一些细微的差别。请注意,这些容器并没有永远存在:
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)
我认为写和读更直观。另外,您可以为 mypy 提供更多检查的可能性:
class UserTuple(NamedTuple):
name: str
gender: Gender
# vs
UserTuple = namedtuple("UserTuple", ["name", "gender"])
Run Code Online (Sandbox Code Playgroud)
如果我不需要事物可变,我喜欢它们不是可变的。这样我可以防止意外的副作用
A TypedDict(在 3.8+ 中)是
一个简单的类型命名空间。在运行时,它相当于一个普通的 dict。
而 aNamedTuple是“元组子类”。注意
命名元组实例没有每个实例的字典,因此它们是轻量级的,不需要比常规元组更多的内存。
和(从这里)
NamedTuple 子类也可以有文档字符串和方法
用我自己的话来说,aNamedTuple更像是一个自定义对象,而 aTypedDict更像是一个类型化的字典。
我没有检查过,但是从这些描述中,我希望NamedTuples比TypedDicts有一些(小的)运行时和内存优势。
但是,例如,如果您正在使用需要 a 的 API,则dictaTypedDict可能更可取,因为它是 a dict(尽管您也可以通过其方法dict从 a创建 a )。NamedTuple_asdict()
来自Steven F. Lott 和 Dusty Phillips 所著的优秀著作《Python 面向对象编程》 :
\n\n\n\n
\n- 对于很多情况,
\ndataclasses可以通过更少的代码编写来提供许多有用的功能。它们可以是不可变的,也可以是可变的,为我们提供了广泛的\xc2\xa0选项。- 对于数据不可变的情况,a 的
\nNamedTuple效率可能比 freeze 的效率高dataclass大约 5% \xe2\x80\x93 不多。这里打破平衡的是昂贵的属性计算。虽然 aNamedTuple可以具有属性,但如果计算成本非常高并且结果被频繁使用,它可以帮助提前计算它,这NamedTuple是 a 不擅长的。查看文档dataclasses及其__post_init__()在极少数情况下,提前计算属性值很有帮助,请- 当事先不知道完整的键集时,字典是理想的选择。当我们开始设计时,我们可能有一次性原型或使用字典的概念证明。当我们尝试编写单元测试和类型提示时,我们可能需要加强形式。在某些情况下,可能的键的域是已知的,并且
\nTypedDict类型提示作为表征有效键和值类型的一种方式是有意义的。