Как / почему работает синтаксис намеков типа 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?

1 ответов


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

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

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

>>> '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 3107; в частности проект mypy (который зацикливается обратно, приняв PEP 484), но и введите поддержку намеков в PyCharm IDE и проект pytypedecl. Увидеть Гвидо ван Россума оригинальная электронная почта kickstarting это усилие а также по электронной почте.

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

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