Подтвердить что ты не робот

Как/почему работает синтаксис намека на тип Python?

Я только что видел следующий пример в PEP 484:

def greeting(name: str) -> str:
    return 'Hello ' + name

print(greeting('Martin'))
print(greeting(1))

Как и ожидалось, это не работает в Python 2:

  File "test.py", line 1
    def greeting(name: str) -> str:
                     ^
SyntaxError: invalid syntax

Однако он работает для Python 3:

Hello Martin
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(greeting(1))
  File "test.py", line 2, in greeting
    return 'Hello ' + name
TypeError: Can't convert 'int' object to str implicitly

Это было неожиданно. Он пока еще не проверяет типы, как вы можете видеть в следующем примере (он запускается, но не генерирует исключение):

def greeting(name: str) -> int:
    return 'Hello ' + name

print(greeting('Martin'))

Кажется, что после : должно быть имя функции, но функция, кажется, игнорируется:

def aha(something):
    print("aha")
    return something+"!"

def greeting(name: aha, foo) -> int:
    return 'Hello ' + name + foo

print(greeting('Martin', 'ad'))

То же самое верно для имени после ->.

Является ли этот тип синтаксисом намека на использование чего-то другого (например, язык моделирования Java использует комментарии)? Когда этот синтаксис был введен в Python? Есть ли способ сделать статический контроль типов уже с этим синтаксисом? Всегда ли он прерывает совместимость с Python 2?

4b9b3361

Ответ 1

Здесь нет никаких намеков. Все, что вы сделали, это аннотации; они были введены с PEP 3107 (только в Python 3, в Python 2 нет поддержки); они позволяют вам комментировать аргументы и возвращать значения с произвольной информацией для последующей проверки:

>>> greeting.__annotations__
{'name': <class 'str'>, 'return': <class 'str'>}

В противном случае они вообще не консультируются. Вместо этого сообщение об ошибке, полученное вами, связано с попыткой конкатенации строковых и целочисленных значений в теле функции:

>>> 'Hello ' + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

Это ошибка настраиваемого типа, направленная на предоставление дополнительной информации о том, почему конкатенация str + int не удалась; он вызывается методом str.__add__ для любого типа, который не является str:

>>> ''.__add__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> ''.__add__(True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bool' object to str implicitly

PEP 484 затем предлагает использовать эти аннотации для выполнения фактической проверки статического типа с помощью дополнительных инструментов, но поскольку введение состояний PEP:

Хотя эти аннотации доступны во время выполнения с помощью обычного атрибута __annotations__, проверка типов не выполняется во время выполнения. Вместо этого в предложении предполагается наличие отдельного контролера типа off-line, который пользователи могут запускать поверх своего исходного кода добровольно. По сути, такая проверка типа действует как очень мощный linter.

Акцент в оригинале.

PEP был вдохновлен существующими инструментами, использующими аннотации PEP 3107; в частности проект mypy (который зацикливается, приняв PEP 484), но также поддержку поддержки подсказок типа в среде PyCharm IDE и проект pytypedecl. См. Guido van Rossum оригинальное письмо, начинающее это усилие, а также последующее письмо.

mypy, по-видимому, поддерживает Python 2 путем предварительной обработки аннотаций, удаляя их перед байтом, компилируя исходный код для вас, но в противном случае вы обычно не можете использовать синтаксический код Python, предназначенный для работы в Python 2.

PEP 484 также описывает использование файлов-заглушек, которые располагаются рядом с обычными файлами Python; они используют расширение .pyi и содержат только сигнатуры (с подсказками типов), оставляя без комментариев основную аннотацию файлов .py и, следовательно, пригодную для использования на Python 2 (при условии, что вы написали код Polyglot Python в противном случае).