列表理解测试中的变量被视为未在python3的exec中定义

时间:2019-06-20 10:09:10

标签: python python-3.x

首先,请注意,这与其他有关exec内部变量的SO问题不同。这对于执行程序中列表理解 TEST 中使用的变量是个问题。

参加此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()

执行时我有这个:

$ 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

usersflag都在exec()中定义。两者都用于列表理解。但只有flag被视为未定义,因为它在测试中使用。

我可以使用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()

执行时我得到:

$ 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

一切都很好,但我希望some_result是本地的,而不是全局的。

为此,我使用了另一个关于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()

,但flag上的未定义再次出现:

$ 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

编辑:

我可以这样解决:

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()

我明白了:

myglob_var = my global var
list comprehension = ['root', 'service']
list comprehension with test = ['root', 'service']
Result = a result

看起来不错,除了在我的实际应用程序中,变量赋值在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()

这一次,它再次触发了相同的问题:exec中定义了users,但没有flag

$ 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

我想在exec内部:使用全局变量,传递函数局部变量,能够在本地返回结果并在列表理解测试中使用变量。我还看不到解决方案:您有个主意吗?

2 个答案:

答案 0 :(得分:2)

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']

     

使用test = ['root','service']的列表理解

     

结果=结果

exec函数仅可用于一个namespace词典。将nm变量设置为局部变量的命名空间。

更新

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()

是否适合在名称空间中定义真正需要的变量?

更新2:

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

如何将局部变量传递给名称空间?

答案 1 :(得分:0)

我终于找到了解决方案,但是我发现这真的很丑:

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()
    nm.update(locals())
    exec(s, nm)
    print('Result =',nm.get('some_result'))


myfunc()

它给出:

$ python3 test.py
myglob_var = my global var
list comprehension = ['root', 'service']
list comprehension with test = ['root', 'service']
Result = a result

它没有解释为什么当我在exec()中指定locals参数时,它会导致列表理解测试中的唯一变量未定义...