2 回答
TA贡献1856条经验 获得超17个赞
Python 及其社区正在努力解决“结构”问题:如何最好地将相关值分组到复合数据对象中,以允许逻辑/轻松访问组件(通常按名称)。有许多相互竞争的方法:
collections.namedtuple
实例字典(带有一组固定/已知的键)
属性可访问的字典(如stuf)
该ATTRS库
PEP 557数据类
为每种结构类型手工制作的普通旧定制对象
每个位置/插槽的类似
tuple
和list
隐含含义的序列(过时但非常常见)等。
“应该有一种——最好只有一种——明显的方法来做到这一点。”
无论是typing
图书馆和Mypy,像在大的Python社区,同时与如何更有效地定义类型/模式,包括复合对象挣扎。您链接到的讨论是努力寻找前进道路的一部分。
NamedTuple
是collections.namedtuple
工厂产生的结构化对象的类型超类;TypedDict
a 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
尽管存在分歧,两者NamedTuple并TypedDict锁定特定的键被使用,并且该类型的对应于每个键的值。因此,它们的目标基本相同:成为复合/结构类型的有用类型机制。
Python 的标准typing.Dict侧重于更同质的并行映射,定义键/值类型,而不是键本身。因此,它在定义碰巧存储在字典中的复合对象时不是很有用。
ConnectionOptions = Dict[str, str]
TA贡献1846条经验 获得超7个赞
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)
为什么我更喜欢 NamedTuple 而不是 namedtuple
我认为写和读更直观。另外,您可以为 mypy 提供更多检查的可能性:
class UserTuple(NamedTuple):
name: str
gender: Gender
# vs
UserTuple = namedtuple("UserTuple", ["name", "gender"])
为什么我更喜欢元组而不是字典
如果我不需要事物可变,我喜欢它们不是可变的。这样我可以防止意外的副作用
添加回答
举报