简体   繁体   中英

NameError: name 'self' is not defined IN EXEC/EVAL

I was coding something, and there was an error in one part. But I can't find why the error occurs.

Code (Sample; similar to the error part):

class Test:
def __init__(self,a=0):
    self.x = a
    self.l = [2**x for x in range(a)]  #<--- self.l = [1,2,4,8,16]
    self.base()

def base(self):
    expr = "self.l{0} = [self.l[x]+{0} for x in range(self.x)]" #<--- when i=4, self.l4 = [5,6,8,12,20]
    for i in range(self.x):
        exec(expr.format(i))

w = Test(5)
print(w.l4)

So I thought that I get this:

[5, 6, 8, 12, 20]

BUT,

File "D:/Documents and Settings/Desktop/py/py/test2.py", line 12, in <module>
  w = Test(5)
File "D:/Documents and Settings/Desktop/py/py/test2.py", line 5, in __init__
  self.base()
File "D:/Documents and Settings/Desktop/py/py/test2.py", line 10, in base
  exec(expr.format(i))
File "<string>", line 1, in <module>
File "<string>", line 1, in <listcomp>

NameError: name 'self' is not defined

(Sorry for bad English)

If you use a for loop instead of the list comprehension

it will works.

class Test:
    def __init__(self,a=0):
        self.x = a
        self.l = [2**x for x in range(a)]  #<--- self.l = [1,2,4,8,16]
        self.base()

    def base(self):
        # expr = "self.l{0} = [self.l[x]+{0} for x in range(self.x)]" #<--- when i=4, self.l4 = [5,6,8,12,20]
        expr = '''
self.l{0} = []
for x in range(self.x):
    self.l{0}.append(self.l[x]+{0})
'''
        for i in range(self.x):
            expr_formated = expr.format(i)
            print(expr_formated)
            exec(expr_formated)

w = Test(5)
print(w.l4)

The list comprehension is actually using lamda function, as you can see in the python document . squares = [x**2 for x in range(a)] is actually squares = list(map(lambda x: x**2, range(a))) . (EDIT: recently I find that this is not accurate, see my question , they are not the same, but they work in a similar way;perhaps one can still uses the lambda to understand this if doesn't want to refer to python assembly) However, creating a function object (lamda function here) inside the exec() will results in problems. I post question here explaining why creating a function object doesn't work as expected. In short, the __closure__ of the defined lamda function is set to None, making the varible a unavailable when the lamda function is called.

If you insist on using lambda function.

There is also another solution. Please refer to my answer to previous mentioned question for more information.

class Test:
    def __init__(self,a=0):
        self.x = a
        self.l = [2**x for x in range(a)]  #<--- self.l = [1,2,4,8,16]
        self.base()

    def base(self):
        expr = """
def closure_helper_func(self):
    self.l{0} = [self.l[x]+{0} for x in range(self.x)]
closure_helper_func(self)""" #<--- when i=4, self.l4 = [5,6,8,12,20]
        for i in range(self.x):
            expr_formated = expr.format(i)
            # print(expr_formated)
            exec(expr_formated)

w = Test(5)
print(w.l4)

'self' is a special class variable, only used internal, can't read outside a class. The first example needs a return value.

There's no need for eval or exec here.

for i in range(self.x):
    setattr(self, "l{}".format(i), [self.l[x]+i for x in range(self.x)])

Although I don't know why you want to do this; better to keep it as a list rather than dynamically set attributes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM