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

Аннотации переменной типа NameError несогласованность

В Python 3.6 на языке были введены новые Variable Annotations.

Но, когда тип не существует, могут произойти две разные вещи:

>>> def test():
...     a: something = 0
... 
>>> test()
>>> 
>>> a: something = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'something' is not defined

Почему поведение несуществующего типа отличается? Разве это не могло бы заставить вас игнорировать типы undefined в функциях?


Примечания

Пробовал как Python 3.6 RC1, так и RC2 - такое же поведение.

PyCharm выделяет something как "нерешенную ссылку" как внутри, так и снаружи функции.

4b9b3361

Ответ 1

Поведение локальной переменной (т.е. внутри функции), как минимум, описано в разделе Эффекты времени выполнения аннотаций типов:

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

def f():
    x: NonexistentName  # No error.

И далее объясняем разницу для глобальных переменных:

Однако, если он находится на уровне модуля или класса, тогда будет оцениваться тип:

x: NonexistentName  # Error!
class X:
    var: NonexistentName  # Error!

Поведение кажется мне удивительным, поэтому я могу только предположить свое предположение относительно рассуждений: если мы поместим код в модуль, то Python хочет сохранить аннотации.

# typething.py
def test():
    a: something = 0

test()


something = ...

a: something = 0

Затем импортируйте его:

>>> import typething
>>> typething.__annotations__
{'a': Ellipsis}
>>> typething.test.__annotations__
{}

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

... значение наличия локаций, доступных локально, не компенсирует затраты на создание и заполнение словаря аннотаций при каждом вызове функции. Поэтому аннотации на уровне функции не оцениваются и не сохраняются.

Ответ 2

Самый прямой ответ для этого (в дополнение к ответу @wim) поступает из трекера проблем в Github, где обсуждалось это предложение:

[..] Наконец, локальные жители. Здесь я думаю, что мы не должны хранить типы - значение наличия доступных локально доступных аннотаций недостаточно для компенсации затрат на создание и заполнение словаря при каждом вызове функции.

На самом деле, я даже не думаю, что выражение типа должно быть оценено во время выполнения функции. Так, например:

def side_effect():
    print("Hello world")
def foo():
    a: side_effect()
    a = 12
    return a
foo()

не должен печатать ничего. (Контроллер типа также будет жаловаться, что side_effect() не является допустимым типом.)

Из самого BDFL:-), а также не созданный диктофон и не выполняются оценки.

В настоящее время объекты функций хранят только аннотации, указанные в их определении:

def foo(a: int): 
    b: int = 0

get_type_hints(foo)   # from typing
{'a': <class 'int'>}

Создание другого словаря для локальных переменных аннотации, по-видимому, считалось слишком дорогостоящим.

Ответ 3

Вы можете перейти к https://www.python.org/ftp/python/3.6.0/ и загрузить версию RC2, чтобы проверить аннотации, но выпущенная версия, как Вим сказала еще не выпущена. Однако я загрузил и попробовал свой код с помощью интерпретатора Python3.6, и никаких ошибок не появилось.

Ответ 4

Вы можете попробовать написать вот так:

>>>a: 'something' = 0