Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

variables in list comprehension test are seen as not defined in an exec with python3

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 ?

like image 494
Eric Avatar asked Nov 25 '25 21:11

Eric


1 Answers

def myfunc():
    s = """
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, nm)
    print('Result =', nm.get('some_result'))

myfunc()

list comprehension = ['root', 'service']

list comprehension with test = ['root', 'service']

Result = a result

The exec function may be applied just with one namespace dictionary. Make nm variable your namespace for local variables.

Update:

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 = {"myglob_var": myglob_var}
    exec(s, nm)
    print('Result =', nm.get("some_result"))

myfunc()

Is it suitable to you define the variables that you really need in namespace?

Update 2:

    nm = globals().copy()
    nm.update(locals())
    exec(s, nm)

How about pass your local variables to the namespace?

like image 181
MartenCatcher Avatar answered Nov 27 '25 11:11

MartenCatcher



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!