Variable type annotation NameError inconsistency Variable type annotation NameError inconsistency python python

Variable type annotation NameError inconsistency


The behaviour of the local variable (i.e. inside the function) is at least documented in the section Runtime Effects of Type Annotations:

Annotating a local variable will cause the interpreter to treat it as a local, even if it was never assigned to. Annotations for local variables will not be evaluated:

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

And goes on to explain the difference for global variables:

However, if it is at a module or class level, then the type will be evaluated:

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

The behaviour seems surprising to me, so I can only offer my guess as to the reasoning: if we put the code in a module, then Python wants to store the annotations.

# typething.pydef test():    a: something = 0test()something = ...a: something = 0

Then import it:

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

Why it's necessary to store it on the module object, but not on the function object - I don't have a good answer yet. Perhaps it is for performance reasons, since the annotations are made by static code analysis and those names might change dynamically:

...the value of having annotations available locally does not offset the cost of having to create and populate the annotations dictionary on every function call. Therefore annotations at function level are not evaluated and not stored.


The most direct answer for this (to complement @wim's answer) comes from the issue tracker on Github where the proposal was discussed:

[..] Finally, locals. Here I think we should not store the types -- the value of having the annotations available locally is just not enough to offset the cost of creating and populating the dictionary on each function call.

In fact, I don't even think that the type expression should be evaluated during the function execution. So for example:

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

should not print anything. (A type checker would also complain that side_effect() is not a valid type.)

From the BDFL himself :-) nor a dict created nor evaluation being performed.

Currently, function objects only store annotations as supplied in their definition:

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

Creating another dictionary for the local variable annotations was apparently deemed too costly.


You can go to https://www.python.org/ftp/python/3.6.0/ and download the RC2 version to test annotations but the released version as wim said is not yet released. I did however downloaded and tried your code using the Python3.6 interpreter and no errors showed up.