Ошибка Mypy на dict of dict: значение типа «объект» не индексируется - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть следующий словарь на python:

dictionary = {'key1': 1,
              'sub_dict': {'key2': 0}
             }

Когда я запускаю mypy в следующей строке:

print(dictionary['sub_dict']['key2'])

возникает ошибка Value of type "object" is not indexable

1 Ответ

0 голосов
/ 20 февраля 2019

Статическая печать сложна.mypy может определить, что значения dictionary не все имеют одинаковый тип, но это далеко.Тип static dictionary равен Dict[str,object], в зависимости от начального значения.Тем не менее, mypy не пытается моделировать код дальше, что означает, что он понятия не имеет, если d['sub_dict'] равно все еще другому dict в точке, где вы пытаетесь проиндексировать его с помощью key2, что приводит к ошибке типа.

Одна вещь, которую вы можете сделать, - это помочь mypy, сказав, что определенное значение можно рассматривать как имеющий определенный тип, используя typing.cast.

print(typing.cast(typing.Dict[str,dict], d['sub_dict'])['key2'])

Во время выполнения typing.cast фактически является функцией идентификации;он просто возвращает свой второй аргумент.mypy рассматривает его как более сильный тип подсказки, говоря, что независимо от любых предыдущих подсказок или аннотаций, d['sub_dict'] следует рассматривать как Dict[str,dict].

Обратите внимание, что при использовании cast,вы говорите mypy, что вы берете на себя ответственность за то, чтобы dictionary['sub_dict'] на самом деле был dict во время выполнения, поскольку это не то, что вы можете передать статическим типом.Вы можете подумать, что что-то вроде

dictionary : Dict[str,Union[int,dict]] = ...

будет работать, но это просто говорит mypy, что было бы ошибкой типа написать dictionary['foo'] = 'bar', поскольку 'bar' не является ни int, ниdict.Даже с более точной подсказкой типов у mypy нет возможности узнать, к какому типу значения dictionary соответствует какой-либо конкретный ключ.

Вы также можете использовать Any:

dictionary: Dict[str,Any] = ...

потому что теперь вы говорите, что в качестве значения можно использовать любой тип, и что любой тип может быть принят в качестве результата индексации, и эти два типа не должны быть выстроены в линию,То есть, dictionary['key1'] = 3 хорошо, потому что int совместимо с Any, но dictionary['sub_dict']['key2'] также хорошо, потому что то, что производит dictionary['sub_dict'], также совместимо с Any, и вы можете предположить, чточто этот тип сам по себе индексируется.По сути, он охватывает любое использование dictionary в любом месте вашего кода, а не в конкретном месте, где вы использовали cast, чтобы утверждать, что должно быть разрешено.


Большое отступление: существует понятие зависимых типов , простейшим примером которого является тип, подобный PositiveInt, который будет идентичен int, за исключением того, что он не допускает отрицательных значений.Казалось бы, dictionary имеет похожий зависимый тип, где тип значений действительно является функцией фактических данных, хранящихся в значении.Например, представьте, что вы могли бы использовать экземпляр из dict с Dict для указания типа его значений.

dictionary: Dict[str, {"key1": int, "sub_dict": dict}] = {'key1': 1,
          'sub_dict': {'key2': 0}
         }

Теперь не только mypy может сказатьчто dictionary['key1'] должен быть int, но сам по себе dictionary никогда не может иметь никаких ключей , кроме , чем key1 и sub_dict.(И в этом гипотетическом мире defaultdict может сопоставить произвольный неуказанный ключ типу по умолчанию.)

...