Search code examples
pythonclassstaticiteratornameerror

Python Classes: NameError: name 'foo' is not defined


Why does accessing the class attribute foo fail when building a tuple with non-zero length only?

class Foo:
    foo = 42
    
    bar_ok1 = (foo for _ in range(10))
    bar_ok2 = tuple(foo for _ in [])
    
    bar_fail1 = tuple(foo for _ in range(10))
    bar_fail2 = tuple(foo for _ in [0, 1, 2])
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    class Foo:
  File "main.py", line 7, in Foo
    bar_fail1 = tuple(foo for _ in range(10))
  File "main.py", line 7, in <genexpr>
    bar_fail1 = tuple(foo for _ in range(10))
NameError: name 'foo' is not defined

Solution

  • That's because bar_ok1 is not evaluated yet, as it defines a generator, and the foo value is not accessed on class definition. The foo value is also not accessed for bar_ok2, as does it not perform the iteration at all (empty list).

    In contrast, the bar_fail* attributes are evaluated on class definition.

    Run the following and you will notice it fails for bar_ok1:

    class Foo:
        foo = 42
        
        bar_ok1 = (foo for _ in range(10))
        bar_ok2 = tuple(foo for _ in [])
        
        #bar_fail1 = tuple(foo for _ in range(10))
        #bar_fail2 = tuple(foo for _ in [0, 1, 2])
    
    list(Foo.bar_ok1)
    list(Foo.bar_ok2)
    

    list(Foo.bar_ok2) will produce an empty list, as there are no elements to loop over and no reason to check the foo value.