为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

素胚勾勒不出你 2021-08-24 15:14:51
在我看来,NamedTuple和TypedDict非常相似,Python 开发人员自己也认识到了这一点。关于 PEP,我宁愿添加一个关于 NamedTuple 和 TypedDict 的公共部分,它们非常相似,后者在结构上已经表现得很好。你怎么看? 但是Guido似乎对此不太确定。我不太确定 NamedTuple 和 TypedDict 是否真的那么相似(除了它们都试图在静态类型的世界中处理过时的模式)。所以,这是我懒惰的尝试,让其他人在官方文档似乎缺乏的情况下提出清晰的比较。
查看完整描述

2 回答

?
慕慕森

TA贡献1856条经验 获得超17个赞

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

  • collections.namedtuple 实例

  • 字典(带有一组固定/已知的键)

  • 属性可访问的字典(如stuf

  • ATTRS

  • PEP 557数据类

  • 为每种结构类型手工制作的普通旧定制对象

  • 每个位置/插槽的类似tuplelist隐含含义的序列(过时但非常常见)

  • 等。

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

无论是typing图书馆和Mypy,像在大的Python社区,同时与如何更有效地定义类型/模式,包括复合对象挣扎。您链接到的讨论是努力寻找前进道路的一部分。

NamedTuplecollections.namedtuple工厂产生的结构化对象的类型超类;TypedDicta 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] 


查看完整回答
反对 回复 2021-08-24
?
喵喵时光机

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"])

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

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


查看完整回答
反对 回复 2021-08-24
  • 2 回答
  • 0 关注
  • 312 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信