I'm trying to code a dictionary inside my class:
data = {element:eval("self.%s" %element) for element in key}
and I've got this error:
data = {element:eval("self.%s" %element) for element in key}
File "<string>", line 1, in <module>
NameError: name 'self' is not defined
If I do:
for element in key:
data[element]=eval("self.%s" %element)
No error here.
How come?
Avoid using
eval
. A better practice is to usegetattr
:TL:DR Summary -
As stated correctly by @CoryKramer , partially this is because dictionary comprehension/list comprehension/generator expressions/nested funcions all are evaluated in their own scope. But other half of the reason for this issue is because of the use of
eval()
, which executes its expressions in the environment in which it is called , but it does not have access to enclosing namespaces.Alternatively ,I believe you should not use
eval()
(its pretty dangerous) . For getting attributes fromself
, you should usegetattr()
function -My findings about the issue for those who are interested -
Partially this is because dictionary comprehension/list comprehension/generator expressions/nested funcions all are evaluated in their own scope. But other half of the reason for this issue is because of the use of
eval()
.As given in the documentation for
eval()
-(Emphasis mine)
Normally inside a class , when you use dictionary comprehension you can use
self
and etc in that dictionary comprehension. Example -As you can see it was possible to access
self.a
within the dictionary comprehension. So now lets check what is thelocals()
(local namespace) for the dictionary comprehension -Result -
As can be seen
'self'
is accessible inside the dictionary comprehension (as its a free variable , and this only occured because I usedself.a
directly inside the dictionary comprehension , if I did not add that it wouldn't be a free variable there. Lets explain free variables a bit -But when you use
eval()
to execute the expression, Python does not know about any names (beforehand, before executing the expression) that are used inside theeval()
, hence it cannot bind theself
as a free variable to the dicitonary comprehension. Example of print oflocals()
, when usingeval
to getself.a
-Result -
Hence, when the expression is evaluated inside the eval it does not have the
self
variable defined in the environment it is executed. If you were to useself
anywhere inside the dictionary comprehension , you would not end up with this error -Result -
Because then the environment in which
eval
expression is getting executed has knows about the name bindingself
.The exact same issue can be replicated using nested functions as well -