Установлена ​​ли проверка типа (набора текста) в словаре Python 3.x при создании экземпляра - PullRequest
0 голосов
/ 05 июля 2018

У меня есть словарь конфигурации, который я загружаю со значениями в иерархии вызовов инициализации dunder, каждый вызов создает часть конфигурации. Пытаясь добавить печатание к этому, я получил странное поведение (или, возможно, я делаю что-то не так). Поведение, которое я получаю, согласуется со словарем, выдающим типы, которые были вставлены в него только в его первом объявлении, обновление расширений и добавление ключей, по-видимому, не изменяет типы, которые словарь объявляет по возможности при доступе к нему, это просто код, который я написал для иллюстрации проблемы:

import re


def foo(a: int = 1, b: str = "b"):
    d = {"a": a}
    d.update({"b": b})
    print(re.findall(d["b"], "baba"))


foo()

Код, конечно, работает и выводит ['b', 'b'] (без каламбура), но мой пикарм выдает два предупреждения:

  1. в строке обновления: Unexpected type(s):<br>(Dict[str, str])<br>Possible types:<br>(Mapping[str, int])<br>(Iterable[Tuple[str, int]])
  2. в строке поиска: Expected type 'Union[bytes, str, __Regex]', got 'int' instead

Мои вопросы: является ли мой анализ причины этой истины (диктует ли его типизацию при создании экземпляра)? и есть ли питонный способ исправить эти предупреждения?

1 Ответ

0 голосов
/ 06 июля 2018

Обновление расширения и добавления ключей, по-видимому, не изменяет типы, которые объявлен в словаре

Это по замыслу. Если у вас есть переменная, объявленная как тип Dict[str, int], вы, вероятно, захотите, чтобы mypy жаловалась очень громко, если вы случайно попытаетесь запустить такой код, как var['foo'] = 'bar'.

В этом случае, так как вы присвоили d набору строки для ints, mypy предполагает, что вы подразумеваете, что для этого типа будет просто Dict[str, int].

Если вы хотите, чтобы ваш код проверялся, у вас есть несколько вариантов:

  1. Явно объявляйте, какие типы значений в вашем словаре ожидаются, и используйте утверждения или приведения, чтобы подтвердить, что типы определенных ключей соответствуют вашим ожиданиям:

    def foo(a: int = 1, b: str = "b") -> None:
        d: Dict[str, Union[int, str]] = {"a": a}
        d.update({"b": b})
    
        # If you want to check your assumption at runtime
        b_regex = d["b"]
        assert isinstance(b_regex, str)
        print(re.findall(b_regex, "baba"))
    
        # If you don't want/don't need to check the type
        print(re.findall(cast(str, d["b"]), "baba"))
    
  2. Откажитесь от статического набора текста и сделайте значение динамическим «Любой» :

    def foo(a: int = 1, b: str = "b") -> None:
        d: Dict[str, Any] = {"a": a}
        d.update({"b": b})
        print(re.findall(d["b"], "baba"))
    
  3. Используйте расширение TypedDict mypy , чтобы указать, что dict будет содержать только определенные строковые ключи, где каждый ключ имеет соответствующее значение определенного типа.

    Обратите внимание, что в настоящее время это расширение только для mypy, хотя в ближайшем будущем планируется добавить его в PEP 484 в качестве полноценного типа. Как только это произойдет, PyCharm фактически обязан понимать TypedDict (хотя возможно, что они уже продвинулись и добавили поддержку на ранней стадии, не уверен).

...