Почему вся статическая типизация не выводится? - PullRequest
0 голосов
/ 11 января 2019

Поскольку Python поддерживает аннотации типов, он обеспечивает статическую дисциплину типизации. При работе с AST, создаваемым модулем ast, меня поражает, что, учитывая такую ​​дисциплину, все типы могут быть выведены, не должно быть необходимости в аннотациях типов. Учитывая прагму статической типизации (возможно, комментарий в верхней части файла кода), дополнительный уровень логики в синтаксическом анализаторе может проходить через AST для определения типов всех переменных.

Например, возьмите этот фрагмент кода с сайта Mypy :

d = {}  # type: Dict[str, int]

with open(sys.argv[1]) as f:
    for s in f:
        for word in re.sub('\W', ' ', s).split():
            d[word] = d.get(word, 0) + 1

DICT d и его ключи и значения набираются с комментарием, но тип может быть выведен из следующего цикла: s - это str, если оно находится в f, содержимое читается из файла; и значение элемента dict равно int, потому что это то, что возвращает выражение присваивания.

Это тот случай, когда выполнение такого анализа кода, как правило, слишком дорого для статической типизации, чтобы быть выведенным, или я что-то упускаю?

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

1 Ответ

0 голосов
/ 11 января 2019

Проблема в том, что аннотации типов являются необязательными. Действительно, модуль re не имеет аннотаций типов, даже в Python 3.8, казалось бы. Конечно, анализатор может проанализировать код Python, чтобы увидеть, что происходит. Тем не менее, для некоторого кода (например, модуля re) код в конечном итоге погружается в C-API (в CPYthon). На этом этапе анализатор не может выяснить, что является сигнатурой типа функции. Как люди, мы можем читать документацию и знать, что re.sub всегда возвращает экземпляр str, но автоматизированные инструменты не могут узнать, если им не предоставляется дополнительная информация о типе.

Тогда у вас проблема в том, что некоторые функции возвращают объединения типов. например. оператор ** (int.__pow__), который возвращает int, float или complex в зависимости от типов и значений его операндов. например.

>>> 3 ** 2
9
>>> 3 ** -2
0.1111111111111111
>>> 2 ** 0.5
1.4142135623730951
>>> (-1) ** 0.5
(6.123233995736766e-17+1j) # should really just be 1j

Это означает, что, учитывая:

def f(x: int, y: int):
   z = x ** y

z будет присвоен тип object (общая база int, float и complex), что, скорее всего, не то, что требуется. Присваивая переменной аннотацию типа, мы можем разрешить mypy выполнять проверку типов при присваивании z результата x ** y, но любые будущие операции с z могут смело предполагать, что тип z будет любым это было определено как.

...