First, note that it is not like other SO questions about variables inside an exec. here it is a problem for a variable used in a list comprehension TEST within an exec.
Take this test.py :
myglob_var = 'my global var'
def myfunc():
s = """
print('myglob_var =',myglob_var)
users = ['root','service']
flag = True
c_list = [ u for u in users ]
print('list comprehension =',c_list)
c_list_with_test = [ u for u in users if flag ]
print('list comprehension with test =',c_list_with_test)
some_result = 'a result'
"""
exec(s)
myfunc()
When executing I have this :
$ python3 test.py
myglob_var = my global var
list comprehension = ['root', 'service']
Traceback (most recent call last):
File "test.py", line 18, in <module>
myfunc()
File "test.py", line 15, in myfunc
exec(s)
File "<string>", line 7, in <module>
File "<string>", line 7, in <listcomp>
NameError: name 'flag' is not defined
both users
and flag
are defined inside the exec(). both are used in list comprehension. but only flag
is seen as undefined because it is used inside a test.
I can workaround that by using exec(s,globals())
:
myglob_var = 'my global var'
def myfunc():
s = """
print('myglob_var =',myglob_var)
users = ['root','service']
flag = True
c_list = [ u for u in users ]
print('list comprehension =',c_list)
c_list_with_test = [ u for u in users if flag ]
print('list comprehension with test =',c_list_with_test)
some_result = 'a result'
"""
exec(s, globals())
print('some_result as global var =',globals().get('some_result'))
print('some_result as local var =',locals().get('some_result'))
myfunc()
when executing I get :
$ python3 test.py
myglob_var = my global var
list comprehension = ['root', 'service']
list comprehension with test = ['root', 'service']
some_result as global var = a result
some_result as local var = None
Everything is fine except I want the some_result
to be local and not global.
to do so, I used a recipe from another question on SO :
myglob_var = 'my global var'
def myfunc():
s = """
print('myglob_var =',myglob_var)
users = ['root','service']
flag = True
c_list = [ u for u in users ]
print('list comprehension =',c_list)
c_list_with_test = [ u for u in users if flag ]
print('list comprehension with test =',c_list_with_test)
some_result = 'a result'
"""
nm = {}
exec(s, globals(), nm)
print('Result =',nm.get('some_result'))
myfunc()
but the undefined on flag
appear again :
$ python3 test.py
myglob_var = my global var
list comprehension = ['root', 'service']
Traceback (most recent call last):
File "test.py", line 18, in <module>
myfunc()
File "test.py", line 15, in myfunc
exec(s, globals(), nm)
File "<string>", line 7, in <module>
File "<string>", line 7, in <listcomp>
NameError: name 'flag' is not defined
EDIT :
I can workaround like this :
myglob_var = 'my global var'
def myfunc():
s = """
print('myglob_var =',myglob_var)
users = ['root','service']
flag = True
c_list = [ u for u in users ]
print('list comprehension =',c_list)
c_list_with_test = [ u for u in users if flag ]
print('list comprehension with test =',c_list_with_test)
some_result = 'a result'
"""
nm = globals().copy()
exec(s, nm)
print('Result =',nm.get('some_result'))
myfunc()
I get this :
myglob_var = my global var
list comprehension = ['root', 'service']
list comprehension with test = ['root', 'service']
Result = a result
It looks fine except that in my real application, variable assignments are before the exec :
myglob_var = 'my global var'
def myfunc():
flag = True
users = ['root','service']
s = """
print('myglob_var =',myglob_var)
c_list = [ u for u in users ]
print('list comprehension =',c_list)
c_list_with_test = [ u for u in users if flag ]
print('list comprehension with test =',c_list_with_test)
some_result = 'a result'
"""
nm = globals().copy()
exec(s, nm, locals())
print('Result =',nm.get('some_result'))
myfunc()
And this time, it triggers again the same problem : users
is defined but not flag
inside the exec :
$ python3 test.py
myglob_var = my global var
list comprehension = ['root', 'service']
Traceback (most recent call last):
File "test.py", line 19, in <module>
myfunc()
File "test.py", line 15, in myfunc
exec(s, nm, locals())
File "<string>", line 5, in <module>
File "<string>", line 5, in <listcomp>
NameError: name 'flag' is not defined
I would like inside the exec : use global variables, pass function local variables, be able to return a result locally AND use a variable in a list comprehension test. I cannot see a solution yet : Do you have an idea ?