Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get this NameError in a generator within a Python class definition?

In Python 3.5.0 this code:

a = (1,2)
class Foo(object):
    b = (3,4)
    c = tuple((i,j) for j in b for i in a)
    d = tuple((i,j) for i in a for j in b)

produces:

Traceback (most recent call last):
  File "genexprtest.py", line 2, in <module>
    class Foo(object):
  File "genexprtest.py", line 5, in Foo
    d = tuple((i,j) for i in a for j in b)
  File "genexprtest.py", line 5, in <genexpr>
    d = tuple((i,j) for i in a for j in b)
NameError: name 'b' is not defined

Why do I get this error? And why do I not get this error on the previous line?

like image 937
Wangnick Avatar asked Oct 29 '15 15:10

Wangnick


People also ask

How do I fix the NameError in Python?

The Python "NameError: name is not defined" occurs when we try to access a variable or function that is not defined or before it is defined. To solve the error, make sure you haven't misspelled the variable's name and access it after it has been declared.

Why am I getting name errors in Python?

What Is a NameError in Python? In Python, the NameError occurs when you try to use a variable, function, or module that doesn't exist or wasn't used in a valid way. Some of the common mistakes that cause this error are: Using a variable or function name that is yet to be defined.

Is NameError a syntax error?

A syntax error occurs when a programmer writes an incorrect line of code. Most syntax errors involve missing punctuation or a misspelled name.


2 Answers

This is because the expression for i in a has a local variable scope, and expression for j in b is inside the scope, thus, no b is found.
Actually, if you write c = tuple((i, j) for i in a for j in b), it will throw the same exception.

The solution is put b into scope of class definition (as you already did) and refer it by self.b.

like image 78
Hou Lu Avatar answered Oct 07 '22 00:10

Hou Lu


I spent ages experimenting and I have a theory about why you're getting this error. I'm not certain but this does explain why it works for c and not for d. I hope this helps you, comment if you disagree :)

def Tuple(this):
    print(a) # this always works
    try:
        print(b) # this always gives an error
    except NameError:
        print("...b is not defined")
    try:
        return tuple(this) # this only gives an error for d and e
    except NameError:
        print("...couldn't make it a tuple")


a = (1,2)     
class Foo(object):
    b = (3,4)
    c = Tuple((i,j) for j in b for i in a)
    d = Tuple((i,j) for i in a for j in b)
    e = Tuple((i,j,k) for i in a for j in b for k in (5, 6))
    f = Tuple((i,j,k) for j in b for i in (5, 6) for k in a)

    print("\nc:", c,"\nd:", d,"\ne:", e,"\nf:", f)

What happened: every time I called the Tuple() function, b was not defined, but a was always defined. This explains why you get an error for d and e but it doesn't explain why c and f work even though b is 'not defined'

My theory: The first for loop is calculated before the whole thing is converted into a tuple. For example, if you tried to do this: Tuple((a, b, c) for a in loop1, for b in loop2 for c in loop3), in the Foo class it would calculate for a in loop1 first, then it would move to the foo and calculate the loops 2 and 3.

In summary:

  1. does first for loop
  2. moves to tuple function
  3. does the remaining loops
  4. the error occurs if a variable in the 2nd or 3rd loop is in class Foo
like image 41
Tom Fuller Avatar answered Oct 07 '22 01:10

Tom Fuller