2 回答

TA貢獻(xiàn)1856條經(jīng)驗(yàn) 獲得超17個(gè)贊
Python 及其社區(qū)正在努力解決“結(jié)構(gòu)”問題:如何最好地將相關(guān)值分組到復(fù)合數(shù)據(jù)對(duì)象中,以允許邏輯/輕松訪問組件(通常按名稱)。有許多相互競爭的方法:
collections.namedtuple
實(shí)例字典(帶有一組固定/已知的鍵)
屬性可訪問的字典(如stuf)
該ATTRS庫
PEP 557數(shù)據(jù)類
為每種結(jié)構(gòu)類型手工制作的普通舊定制對(duì)象
每個(gè)位置/插槽的類似
tuple
和list
隱含含義的序列(過時(shí)但非常常見)等。
“應(yīng)該有一種——最好只有一種——明顯的方法來做到這一點(diǎn)?!?/p>
無論是typing
圖書館和Mypy,像在大的Python社區(qū),同時(shí)與如何更有效地定義類型/模式,包括復(fù)合對(duì)象掙扎。您鏈接到的討論是努力尋找前進(jìn)道路的一部分。
NamedTuple
是collections.namedtuple
工廠產(chǎn)生的結(jié)構(gòu)化對(duì)象的類型超類;TypedDict
a Mypy 嘗試定義使用固定模式字典時(shí)出現(xiàn)的鍵和相應(yīng)類型的值。如果您只是考慮“我有一組固定的鍵應(yīng)該映射到一組固定的鍵入值”,那么它們是相似的。但是由此產(chǎn)生的實(shí)現(xiàn)和約束是非常不同的。袋子和盒子一樣嗎?也許。也許不是。取決于您的觀點(diǎn)以及您想如何使用它們。倒酒,開始討論!
NamedTuple
順便說一下,現(xiàn)在是 Python 的正式組成部分。
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
TypedDict開始作為一個(gè)實(shí)驗(yàn)性的 Mypy 功能開始生活,將打字與字典的異構(gòu)、面向結(jié)構(gòu)的使用進(jìn)行斗爭。然而,從 Python 3.8 開始,它被納入標(biāo)準(zhǔn)庫。
try:
from typing import TypedDict # >=3.8
except ImportError:
from mypy_extensions import TypedDict # <=3.7
Movie = TypedDict('Movie', {'name': str, 'year': int})
還可以使用基于類的類型構(gòu)造函數(shù):
class Movie(TypedDict):
name: str
year: int
盡管存在分歧,兩者NamedTuple并TypedDict鎖定特定的鍵被使用,并且該類型的對(duì)應(yīng)于每個(gè)鍵的值。因此,它們的目標(biāo)基本相同:成為復(fù)合/結(jié)構(gòu)類型的有用類型機(jī)制。
Python 的標(biāo)準(zhǔn)typing.Dict側(cè)重于更同質(zhì)的并行映射,定義鍵/值類型,而不是鍵本身。因此,它在定義碰巧存儲(chǔ)在字典中的復(fù)合對(duì)象時(shí)不是很有用。
ConnectionOptions = Dict[str, str]

TA貢獻(xiàn)1846條經(jīng)驗(yàn) 獲得超7個(gè)贊
NamedTuple
如果可能的話,如果我想凍結(jié)這些值,我會(huì)去。否則我會(huì)使用數(shù)據(jù)類。
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
我認(rèn)為寫和讀更直觀。另外,您可以為 mypy 提供更多檢查的可能性:
class UserTuple(NamedTuple):
? ? name: str
? ? gender: Gender
# vs
UserTuple = namedtuple("UserTuple", ["name", "gender"])
為什么我更喜歡元組而不是字典
如果我不需要事物可變,我喜歡它們不是可變的。這樣我可以防止意外的副作用
添加回答
舉報(bào)