Mypy: Как мне ввести словарь, в котором в качестве ключей используются строки, а значения могут быть строками или списками строк? - PullRequest
0 голосов
/ 12 июля 2020

Я использую Python 3.8.1 и mypy 0.782. Я не понимаю, почему mypy жалуется на следующий код:

from typing import Union, List, Dict
Mytype = Union[Dict[str, str], Dict[str, List[str]]]
s: Mytype = {"x": "y", "a": ["b"]}

Mypy выдает следующую ошибку в строке 3:

Incompatible types in assignment (expression has type "Dict[str, Sequence[str]]", variable has type "Union[Dict[str, str], Dict[str, List[str]]]")

Если я изменю последнюю строку на s: Mytype = {"a": ["b"]} mypy не жалуется. Однако при добавлении еще одной строки s["a"].append("c") приводит к ошибке:

error: Item "str" of "Union[str, List[str]]" has no attribute "append"

Чем объяснить вышесказанное? Как мне ввести dict, в котором в качестве ключей используются строки, а значения могут быть строками или списками строк?

Нашел это: https://github.com/python/mypy/issues/2984#issuecomment -285716826 , но все еще не совсем уверен, почему вышеупомянутое происходит, и как мне это исправить.

EDIT: Хотя до сих пор не ясно, почему предлагаемая модификация Mytype = Dict[str, Union[str, List[str]]] не устраняет ошибку с помощью s['a'].append('c') Я думаю, что подход TypeDict предложенный в комментариях, а также в { ссылка } - это путь к go, поэтому отметьте этот подход как решение.

См. аналогичный вопрос по адресу: Указание нескольких значений в Dict [] для подсказок типа , предложенных в комментариях Георгия.

1 Ответ

2 голосов
/ 12 июля 2020

Потому что s: Mytype не может иметь тип Dict[str, str] и тип Dict[str, List[str]] одновременно. Вы можете делать то, что хотите, вот так:

    Mytype = Dict[str, Union[str, List[str]]]

Но могут быть проблемы, потому что Dict инвариантен

Вы можете использовать TypedDict, но ожидается только фиксированный набор строковых ключей:

from typing import List, TypedDict

Mytype = TypedDict('Mytype', {'x': str, 'a': List[str]})
s: Mytype = {"x": "y", "a": ["b"]}

s['a'].append('c')

ПРИМЕЧАНИЕ:

Если вы не в Python 3.8 или новее (где TypedDict доступен в модуле набора стандартной библиотеки) вам необходимо установить typing_extensions с помощью pip, чтобы использовать TypedDict

И, конечно, вы можете использовать Any:

Mytype = Dict[str, Any]
...