Разница между определением typing.Dict и dict?

Я практикую использование подсказок типа в Python 3.5. Один из моих коллег использует typing.Dict:

import typing


def change_bandwidths(new_bandwidths: typing.Dict,
                      user_id: int,
                      user_name: str) -> bool:
    print(new_bandwidths, user_id, user_name)
    return False


def my_change_bandwidths(new_bandwidths: dict,
                         user_id: int,
                         user_name: str) ->bool:
    print(new_bandwidths, user_id, user_name)
    return True


def main():
    my_id, my_name = 23, "Tiras"
    simple_dict = {"Hello": "Moon"}
    change_bandwidths(simple_dict, my_id, my_name)
    new_dict = {"new": "energy source"}
    my_change_bandwidths(new_dict, my_id, my_name)

if __name__ == "__main__":
    main()

Оба работают нормально, разницы не видно.

Я прочитал typing документацию по модулю.

Между typing.Dict или dict какой из них я должен использовать в программе?


person joe    schedule 07.05.2016    source источник
comment
Обратите внимание, что Python на самом деле не применяет подсказки типов. Это просто подсказки, они не используются во время выполнения или даже во время компиляции для обеспечения соблюдения типов. Python может быть строго типизирован (в отличие от слабой типизации), он также динамически типизирован (в отличие от строгой типизации). См. раздел Является ли Python строго типизированным?. Однако внешние инструменты, такие как mypy, могут использовать эти подсказки, чтобы помочь вам писать более качественный код в процессе, называемом статическим анализом.   -  person Martijn Pieters    schedule 07.05.2016
comment
@MartijnPieters Раньше мне нравилось использовать подсказки типов в моем коде вместе с MyPy и притворяться, что я могу использовать Python с безопасностью типов. К сожалению, это заставило меня: а) код, который не работает на ‹ 3.4 и б) люди смеются надо мной, потому что, по-видимому, подсказки типа являются посмешищем. Это действительно очень прискорбно.   -  person cat    schedule 07.05.2016
comment
@cat: Подсказка типов была введена в Python сотрудником Facebook, потому что мы добились огромного успеха при добавлении той же функции в PHP (см. взломать). Тот, кто смеется, никогда не создавал большой проект с участием более чем горстки инженеров.   -  person Martijn Pieters    schedule 07.05.2016
comment
@cat: MyPy, кстати, поддерживает python 3.2 и выше, а также 2.7.   -  person Martijn Pieters    schedule 07.05.2016
comment
@MartijnPieters Нет, def a(b: int) -> bool: - это синтаксическая ошибка в Python 2.7, и я думаю, что это синтаксическая ошибка и в более старых версиях Python 3.   -  person cat    schedule 07.05.2016
comment
@MartijnPieters Осмелюсь сказать, что все, кроме PHP, было бы лучше, чем PHP, но Hack, кажется, просто пытается сделать PHP еще более Java++-y, чем уже есть разработчики PHP. Хотя не совсем в тему :)   -  person cat    schedule 07.05.2016
comment
@cat: здесь вы говорите об аннотациях функций, синтаксисе, который был добавлен в Python 3.0. Таким образом, единственная версия, где это является синтаксической ошибкой, — это 2.7, поэтому mypy поддерживает размещение этой информации в комментариях.   -  person Martijn Pieters    schedule 07.05.2016
comment
@cat: и в самом деле, теперь мы находимся на территории чата. Если вам интересно, найдите меня в комнате Python. Hack не превращает PHP в Java++-y; здесь нет статической типизации. Это делает PHP более похожим на Python, во всяком случае. Слишком многословно, однако.   -  person Martijn Pieters    schedule 07.05.2016


Ответы (3)


Нет никакой реальной разницы между использованием простых typing.Dict и dict, нет.

Однако typing.Dict является универсальным типом < sup>*, который позволяет указать тип ключей и значений тоже, что делает его более гибким:

def change_bandwidths(new_bandwidths: typing.Dict[str, str],
                      user_id: int,
                      user_name: str) -> bool:

Таким образом, вполне может случиться так, что в какой-то момент жизни вашего проекта вы захотите более точно определить аргумент словаря, и в этот момент расширение typing.Dict до typing.Dict[key_type, value_type] будет "меньшим" изменением, чем замена dict.

Вы можете сделать это еще более общим, используя Mapping или MutableMapping здесь; поскольку вашей функции не нужно изменять сопоставление, я бы остановился на Mapping. dict — это одно сопоставление, но вы можете создать другие объекты, которые также удовлетворяют интерфейсу сопоставления, и ваша функция вполне может работать с ними:

def change_bandwidths(new_bandwidths: typing.Mapping[str, str],
                      user_id: int,
                      user_name: str) -> bool:

Теперь вы четко сообщаете другим пользователям этой функции, что ваш код на самом деле не будет изменять переданное сопоставление new_bandwidths.

Ваша фактическая реализация просто ожидает объект, который можно распечатать. Это может быть тестовая реализация, но в ее нынешнем виде ваш код будет продолжать работать, если вы используете new_bandwidths: typing.Any, потому что любой объект в Python доступен для печати.


*: Примечание. Если вы используете Python 3.7 или новее, вы можете использовать dict в качестве общего типа, если вы начинаете свой модуль с from __future__ import annotations, а начиная с Python 3.9, dict (а также другие стандартные контейнеры) поддерживает использование в качестве общего типа даже без этой директивы.

person Martijn Pieters    schedule 07.05.2016
comment
Полезными дополнительными примерами могут быть, когда значения словаря могут быть разных типов, например. {"name": "bob", "age" : 51}, это что-то вроде typing.Mapping[Union[str, int] ? Как насчет вложенного словаря, такого как {"person": {"name":"bob", "age": 51}, это будет что-то вроде typing.Mapping[str, typing.Mapping[Union[str, int]]? Такое использование Union беспокоит меня, потому что это не строгая схема, так как нет порядка. Может это нормально или есть альтернатива? - person Davos; 04.06.2018
comment
Не обращайте внимания на вопрос Union, я вижу, что это все еще открытое обсуждение github.com/python/typing/issues/ 28 - person Davos; 04.06.2018
comment
@GregHilston: на самом деле речь идет о том, как ограничить, какие ключи может содержать словарь, и указать, какие типы должно иметь каждое связанное значение. - person Martijn Pieters; 21.08.2019
comment
@MartijnPieters указывает, какие типы должно иметь каждое связанное значение. разве это не то, о чем Давос говорит выше? - person Greg Hilston; 21.08.2019
comment
@GregHilston: ах, да, это так. - person Martijn Pieters; 21.08.2019
comment
Мне также сказали, что Mapping[A, B] может принять Mapping[A, B1], где issubclass(B1, B), а Dict[A, B] не может! - person xjcl; 08.12.2020
comment
@xjcl: правильно, см. определения для typing.Mapping ( VT_co = тип значения, ковариантный) и typing.Dict (VT = неизменный). Речь идет о том, что функция может делать. Mapping является неизменяемым, поэтому функция, которая принимает сопоставление со значениями B и B1, будет работать, если она будет обрабатывать все как B. Но Dict допускает мутацию; функция, которая принимает dict со значениями B, вставляет только значения B, поэтому передача Dict[A, B1] нарушит другой код! - person Martijn Pieters; 13.12.2020
comment
@xjcl: см. См. python.org/dev/peps/ pep-0484/#covariance-and-contravariance, чтобы узнать больше. - person Martijn Pieters; 13.12.2020
comment
@xjcl: это не означает, что вы не можете передать {key: Bsubclass()} такой функции, просто словарь там помечен как Dict[A, B], а весь остальной код обрабатывает значения только как экземпляры B() и не использует без явных проверок какие-либо Bsubclass атрибуты. - person Martijn Pieters; 13.12.2020

typing.Dict — это общая версия dict:

class typing.Dict(dict, MutableMapping[KT, VT])

Общая версия dict. Использование этого типа заключается в следующем:

def get_position_in_index(word_list: Dict[str, int], word: str) -> int:
     return word_list[word]

Здесь вы можете указать тип ключа и значения в словаре: Dict[str, int]

person AKS    schedule 07.05.2016

как сказано в python org:

ввод класса.Dict(dict, MutableMapping[KT, VT])

Общая версия dict. Полезно для аннотирования возвращаемых типов. Для аннотирования аргументов предпочтительно использовать абстрактный тип коллекции, такой как Mapping.

Этот тип можно использовать следующим образом:

def count_words(text: str) -> Dict[str, int]:
    ...

Но dict менее общий, и вы сможете изменить переданное сопоставление. Фактически, в python.Dict вы указываете больше деталей.

Еще один совет:

Устарело, начиная с версии 3.9: встроенный файл.dict теперь поддерживает []. См. PEP 585 и общий тип псевдонима.

person Ehsan Barkhordar    schedule 21.04.2021