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

102

Я практикуюсь в использовании подсказок типов в 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какой из них использовать в программе?

Сарит
источник
11
Обратите внимание, что Python фактически не применяет подсказки типов. Это просто подсказки , они не используются во время выполнения или даже во время компиляции для обеспечения типов. Python может быть строго типизированным (в отличие от слабой типизации), он также динамически типизирован (в отличие от строгой типизации). См. Строго ли типизированный Python? . Однако внешние инструменты, такие как mypy, могут использовать эти подсказки, чтобы помочь вам писать лучший код в процессе, называемом статическим анализом.
Мартейн Питерс
1
@MartijnPieters Раньше мне нравилось использовать подсказки типов в моем коде вместе с MyPy и делать вид, что я могу использовать Python с безопасностью типов. К сожалению, у меня получилось: A) код, который не работает на <3.4 и B) люди смеются надо мной, потому что, по-видимому, подсказки типа - посмешище. Это действительно прискорбно.
кот
3
@cat: Подсказка типов была введена в Python сотрудником Facebook, потому что мы добились огромного успеха, добавив ту же функцию в PHP (см. раздел «Взлом» ). Тот, кто смеется, никогда не создавал большой проект с более чем горсткой инженеров.
Мартейн Питерс
3
@MartijnPieters Нет, def a(b: int) -> bool:это синтаксическая ошибка в Python 2.7, и я думаю, что это синтаксическая ошибка и в более старых версиях Python 3.
кот
1
@cat: здесь вы говорите об аннотациях функций , синтаксисе, который был добавлен в Python 3.0. Таким образом, единственная версия, где это синтаксическая ошибка, - 2.7, поэтому mypy поддерживает размещение этой информации в комментариях.
Мартейн Питерс

Ответы:

138

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

Тем не менее, typing.Dictэто тип Generic , который позволяет указать тип ключей и значений тоже , что делает его более гибким:

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. A dict- это одно отображение, но вы можете создать другие объекты, которые также удовлетворяют интерфейсу сопоставления, и ваша функция вполне может работать с ними:

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

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

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

Мартейн Питерс
источник
2
Полезными дополнительными примерами могут быть случаи, когда значения словаря могут быть разных типов, например {"name": "bob", "age" : 51}, будет ли это что-то вроде typing.Mapping[Union[str, int]? А как насчет вложенного словаря, вроде {"person": {"name":"bob", "age": 51}бы это было что-то вроде typing.Mapping[str, typing.Mapping[Union[str, int]]? Такое использование Unionбеспокоит меня, потому что это не строгая схема, поскольку нет упорядочивания. Может это нормально, или есть альтернатива?
Давос
1
UnionНе обращайте внимания на вопрос, который, я вижу, это все еще открытое обсуждение github.com/python/typing/issues/28
Давос
1
Это кажется очень интересным, полезным и связанным с ним python.org/dev/peps/pep-0589
Грег Хилстон
@GregHilston: это на самом деле о том, как ограничить, какие ключи может содержать словарь, и указать, какие типы должно иметь каждое связанное значение.
Мартейн Питерс
1
@GregHilston: а, да, это так.
Мартейн Питерс
26

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: Dict[str, int]

AKS
источник