Как заставить mypy жаловаться на назначение Any на int

mypy --strict покорно жалуется на следующий код:

from typing import Any, Dict

def main() -> None:
    my_str: str = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

путем вывода:

error: Incompatible types in assignment (expression has type "str", variable has type "int")

Однако следующий код принимается без ошибок:

from typing import Any, Dict

def main() -> None:
    my_str: Any = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

Есть ли возможность для mypy заставить его также отклонить второй пример?

Я ожидаю, что это произойдет, потому что он также отвергает следующее:

from typing import Any, Dict, Union

def main() -> None:
    my_str: Union[int, str] = 'hello'
    my_int: int = my_str

if __name__ == "__main__":
    main()

с:

error: Incompatible types in assignment (expression has type "Union[int, str]", variable has type "int")

И в моем понимании Any это всего лишь Union из всех возможных типов.


person Tobias Hermann    schedule 05.08.2018    source источник
comment
Нет, почему он должен отвергать это? Он не может делать никаких утверждений о том, что my_str _может_ быть.   -  person Martijn Pieters    schedule 05.08.2018
comment
См. stackoverflow.com/questions/43910979/ и прочитайте описание ответа на проверку типов Any.   -  person i alarmed alien    schedule 05.08.2018
comment
Возможный дубликат ошибка Mypy - несовместимые типы в назначении   -  person i alarmed alien    schedule 05.08.2018
comment
Любыми способами: извините, я сдаюсь, перестаньте отслеживать это.   -  person Martijn Pieters    schedule 05.08.2018
comment
@MartijnPieters Хороший вопрос. Я добавил объяснение моего ожидания вопроса.   -  person Tobias Hermann    schedule 05.08.2018
comment
Относительно Mypy error - incompatible types in assignment: я не думаю, что мой вопрос является дубликатом этого . Я хочу, чтобы mypy выдавало ошибку. Другой вопрос хочет, чтобы допустимая ошибка исчезла. ;)   -  person Tobias Hermann    schedule 05.08.2018


Ответы (2)


И в моем понимании Any - это всего лишь Union из всех возможных типов.

Это неправильно. Any — это аварийный выход, аннотация для переменных, которые вы хотите, чтобы средство проверки типов игнорировало. Это точно не союз.

Из документации mypy по Any:

Значение типа Any имеет динамический тип. Mypy ничего не знает о возможных типах таких значений во время выполнения. Со значением разрешены любые операции, и операции проверяются только во время выполнения. Вы можете использовать Any как "аварийный выход", когда по какой-либо причине вы не можете использовать более точный тип.

(Жирным выделить мое)

Он явно охватывает ваш случай:

Any совместим с любым другим типом и наоборот. Вы можете свободно присваивать значение типа Any переменной более точного типа:

a: Any = None
s: str = ''
a = 2     # OK (assign "int" to "Any")
s = a     # OK (assign "Any" to "str")

Объявленные (и предполагаемые) типы игнорируются (или стираются) во время выполнения. В основном они обрабатываются как комментарии, и поэтому приведенный выше код не генерирует ошибку времени выполнения, даже несмотря на то, что s получает значение int при запуске программы, в то время как объявленный тип s на самом деле str!

Таким образом, правильным подходом будет не использовать Any, если вы хотите, чтобы средство проверки типов продолжало отслеживать использование значения. Используйте Union[], как в третьем примере, или переосмыслите свои структуры данных, чтобы обеспечить лучшую подсказку типа. Например, вместо использования словаря с типом значения объединения рассмотрите возможность использования именованного кортежа или класса данных с явными полями и определенным типом для каждого поля.

person Martijn Pieters    schedule 05.08.2018
comment
О, большое спасибо за это очень хорошее объяснение. Это отлично отвечает на мой конкретный вопрос (поскольку мое понимание Any было неверным), поэтому я принимаю его. Но, к сожалению, это не решает мою проблему, поэтому я открыл дополнительный вопрос, чтобы не сбивать с толку: stackoverflow.com/questions/51696060/ - person Tobias Hermann; 05.08.2018

Для тех, кто прочитает об этом позже, фактическое решение состоит в том, чтобы использовать семейство флагов командной строки «запретить любые», как описано в этот ответ .

person Tobias Hermann    schedule 05.08.2018