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

时间:2018-11-21 09:40:59

标签: python dictionary types namedtuple mypy

在我看来NamedTupleTypedDict非常相似,Python开发人员自己也意识到了这一点。

  

关于PEP,我宁愿添加有关NamedTuple和TypedDict的公共部分,它们非常相似,后者已经在结构上起作用。你怎么看?   source

但是Guido对此不太确定。

  

我不确定NamedTuple和TypedDict是否真的一样(除了它们都是试图在静态类型的世界中处理过时的模式)。

source

因此,这是我懒惰的尝试,目的是使其他人在官方文档似乎缺乏的情况下进行清晰的比较。

4 个答案:

答案 0 :(得分:4)

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

  • collections.namedtuple实例
  • 词典(具有一组固定/已知的密钥)
  • 可访问属性的字典(如stuf
  • attrs
  • PEP 557 dataclasses
  • 为每种结构类型手工制作的旧定制对象
  • tuplelist之类的序列,每个位置/位置都有隐含含义(古朴但极为普遍)

对于“应该有一种,最好只有一种明显的方式来做到这一点”。

typing库和Mypy(就像整个Python社区一样)都在努力解决如何更有效地定义类型/模式(包括复合对象)的问题。您链接到的讨论是该工作的一部分,并试图找到前进的方向。

NamedTuplecollections.namedtuple工厂产生的结构化对象的输入超类; TypedDict Mypy尝试定义使用固定模式字典时出现的键和相应的值类型。如果您只是在考虑“我有一组固定的键应该映射到一组固定的类型值”,它们是相似的。但是最终的实现方式和约束条件却大不相同。袋子和盒子相似吗?也许。也许不吧。取决于您的观点和使用方式。倒酒,让讨论开始!

顺便说一下,

NamedTuple现在是Python的正式组成部分。

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int

TypedDict不是Python专有的 部分,而是Mypy的一项实验性功能,可将打字打乱到异类的,面向结构的字典使用中。

from mypy_extensions import TypedDict

Movie = TypedDict('Movie', {'name': str, 'year': int})

尽管NamedTupleTypedDict有所不同,但它们都锁定了要使用的特定键以及与每个键对应的值的类型。因此,他们的目标基本上是相同的目标:对复合/结构类型使用有用的键入机制。

Python的标准typing.Dict专注于更均匀的并行映射,定义键/值类型,而不是键本身。因此,在定义碰巧存储在字典中的复合对象时,它并不是很有用。

ConnectionOptions = Dict[str, str] 

答案 1 :(得分:3)

一个TypedDict(在3.8+中)是

简单类型的名称空间。在运行时,它等同于简单的字典。

NamedTuple是“元组子类”。请注意

命名元组实例没有按实例的字典,因此它们是轻量级的,并且不需要比常规元组更多的内存。

和(from here

NamedTuple子类也可以具有文档字符串和方法

用我自己的话来说,NamedTuple更像是自定义对象,而TypedDict更像是类型化的字典。

我还没有检查,但是从这些描述中,我希望NamedTuplesTypedDict拥有一些(较小的)运行时和内存优势。

但是,例如,如果您使用的API期望dict,则最好使用TypedDict,因为它是dict(尽管您也可以创建{ dict中的{1}}通过其NamedTuple方法)。

答案 2 :(得分:1)

有一些细微的差异。请注意,这些容器还没有永远存在过:

如果可能并且我希望冻结值,我会选择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)

答案 3 :(得分:0)

NamedTuple是一种特定类型。顾名思义,这是一个扩展为具有命名条目的元组。

TypedDict不是真实的对象,您不能(或至少不应)使用它,而是用于添加类型信息(用于mypy类型检查器)以在词典中的场景中注释类型具有各种不同类型的键,即基本上所有应该使用NamedTuple的地方。注释您不想重构的现有代码非常有用。

相关问题