Search code examples
pythonlistimporttyping

missing "from typing import List" - error in script, but not in function


I was recently surprised to see that some of our code had a linter warning on the "List" in something equivalent to:

class MyClass:
    def method(self):
        myVar: List[str] = []

The linter warning is because this file is missing from typing import List in the imports. So, PyCharm flags this as a linter error. Certainly the code is incorrect. What's surprising is this code runs, and has run properly for months!

Digging in, I found that this:

class MyClass:
    def method(self):
        myVar: List[str] = []

m = MyClass()
m.method()

And this:

def method(self):
    l: List[str] = []

method(None)

run properly, but this:

l: List[str] = []

Raises the expected error!

Traceback (most recent call last):
  File ".../scratches/scratch_3.py", line 5, in <module>
    l: List[str] = []
NameError: name 'List' is not defined

So... what gives?

(Versions: I am running

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

But the code works on several different versions of PYTHON on WINDOWS and LINUX (UBUNTU) builds.
)


Solution

  • Python treats annotations for global & local variables differently, as outlined in PEP 526. Annotations for module- & class-level variables are evaluated, but annotations for local variables are not.

    This makes some sense, as module- and class-level annotations can be accessed through the __annotations__ dictionary, so it must evaluate the annotation and record it. On the other hand, local variable annotations can not be programmatically accessed, so there's no point in evaluating them.