Мне кажется, что NamedTuple и TypedDict довольно похожи, и сами разработчики Python это признали.
Concerning the PEP, I would rather add a common section about NamedTuple and TypedDict, they are quite similar and the latter already behaves structurally. What do you think? source
Но тогда Гвидо, кажется, не так уверен в этом.
I'm not so sure that NamedTuple and TypedDict are really all that similar (except they are both attempts to handle outdated patterns in a statically-typed world).
Итак, это моя ленивая попытка заставить кого-то другого провести четкое сравнение, хотя официальная документация, похоже, отсутствует.






Python и его сообщество борются с проблемой «структуры»: как лучше всего сгруппировать связанные значения в составные объекты данных, которые обеспечивают логический / легкий доступ к компонентам (обычно по имени). Существуют конкурирующие подходы многие:
collections.namedtuple экземплярыtuple и list, с подразумеваемыми значениями для каждой позиции / слота (архаичный, но чрезвычайно распространенный)Вот и все, что «должен быть один - и желательно только один - очевидный способ сделать это».
И библиотека typing, и Mypy, как и сообщество Python в целом, одновременно борются с тем, как более эффективно определять типы / схемы, в том числе для составных объектов. Обсуждение, с которым вы связались, является частью этой борьбы и попытки найти путь вперед.
NamedTuple - это суперкласс типизации для структурированных объектов, созданных фабрикой collections.namedtuple; TypedDict 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]
Спасибо за отзыв. Вы сознательно пошли на синтаксис TypedDict? Потому что есть также синтаксис на основе классов, который делает их похожими на NamedTuple (с точки зрения синтаксиса)
Я использовал синтаксис документация Mypy. Документы обычно являются лучшим источником того, что считается каноническим / предпочтительным.
Обновление: TypedDict теперь является частью стандартной библиотеки, начиная с Python 3.8! docs.python.org/3/library/typing.html#typing.TypedDict
@KevinLanguasco Спасибо за обновление. Исправленный ответ для размещения.
Думаю, в основном обсуждались сходства, а различий не было.
NamedTuple - это особый тип. Как следует из названия, это кортеж, который расширен за счет именованных записей.
TypedDict не является реальным объектом, вы не можете (или, по крайней мере, не должны) использовать его, вместо этого он используется для добавления информации о типе (для mypy type checker) для аннотирования типов в сценариях, когда в словаре есть разные ключи с разными типами, т.е. практически везде, где следует использовать NamedTuple. Очень полезно аннотировать существующий код, который вы не хотите подвергать рефакторингу.
A simple typed namespace. At runtime it is equivalent to a plain dict.
тогда как NamedTuple является «подклассом кортежа». Обратите внимание, что
Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples.
и (отсюда)
NamedTuple subclasses can also have docstrings and methods
Проще говоря, NamedTuple больше похож на настраиваемый объект, а TypedDict больше похож на типизированный словарь.
Я не проверял, но, судя по этим описаниям, я ожидал, что NamedTuples будет иметь некоторые (небольшие) преимущества по времени выполнения и памяти по сравнению с TypedDict.
Однако, если вы используете API, например, который ожидает dict, TypedDict может быть предпочтительнее, поскольку это dict (хотя вы также можете создать dict из NamedTuple с помощью его метода _asdict()).
Есть пара незначительных отличий. Обратите внимание, что эти контейнеры не были там вечно:
Я бы выбрал 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)
Я считаю, что писать и читать проще. Кроме того, вы даете mypy больше возможностей для проверки:
class UserTuple(NamedTuple):
name: str
gender: Gender
# vs
UserTuple = namedtuple("UserTuple", ["name", "gender"])
Если мне не нужно, чтобы что-то было изменяемым, мне нравится, если это не так. Таким образом я предотвращаю неожиданные побочные эффекты
Вы можете объяснить, почему вы выбрали NamedTuple?
Из отличной книги Стивена Ф. Лотта и Дасти Филлипса «Объектно-ориентированное программирование на Python»
- For a lot of cases, dataclasses offer a number of helpful features with less code writing. They can be immutable, or mutable, giving us a wide range of options.
- For cases where the data is immutable, a NamedTuple can be slightly more efficient than a frozen dataclass by about 5% – not much. What tips the balance here is an expensive attribute computation. While a NamedTuple can have properties, if the computation is very costly and the results are used frequently, it can help to compute it in advance, something a NamedTuple isn't good at. Check out the documentation for dataclasses and their post_init() method as a better choice in the rare case where it's helpful to compute an attribute value in advance.
- Dictionaries are ideal when the complete set of keys isn't known in advance. When we're starting a design, we may have throwaway prototypes or proofs of concept using dictionaries. When we try to write unit tests and type hints, we may need to ramp up the formality. In some cases, the domain of possible keys is known, and a TypedDict type hint makes sense as a way to characterize the valid keys and value types.
namedtupleиdictпохожи на вас?