Почему вся статическая типизация не выводится?
Поскольку Python поддерживает аннотации типов, он обеспечивает статическую дисциплину типизации. При работе с АСТ производится 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
Дикт d
и его ключи и значения набираются с комментарием, но тип может быть выведен из следующего цикла: s
это str
если это в f
содержимое, прочитанное из файла; и значение элемента dict является int
потому что это то, что возвращает выражение присваивания.
Является ли это случаем, что выполнение такого анализа кода обычно слишком дорого для статической типизации, чтобы быть выведенным, или я пропускаю что-то еще?
Обратите внимание, что этот вопрос не относится к обсуждению динамической и статической типизации или необязательной типизации. Моя точка зрения касается определения типа, когда программист соглашается на статическую типизацию.
1 ответ
Проблема в том, что аннотации типов не являются обязательными. Действительно, 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
быть тем, кем он был определен.