exec() 在函数内部不工作 python3.x

exec() not working inside function python3.x

我正在尝试 运行 这段代码,但似乎 exec() 没有执行函数内的字符串:

def abc(xyz):
    for i in fn_lst:
        s = 'temp=' + i + '(xyz)'
        exec(s)
        print (temp)

abc('avdfbafadnf')

我收到的错误:

NameError                                 Traceback (most recent call last)
<ipython-input-23-099995c31c78> in <module>()
----> 1 abc('avdfbafadnf')

<ipython-input-21-80dc547cb34f> in abc(xyz)
      4         s = 'temp=' + i + '(word)'
      5         exec(s)
----> 6         print (temp)

NameError: name 'temp' is not defined

fn_lst 是函数名称列表,即:['has_at', 'has_num' ...]

在这种情况下,如果可能的话,请告诉我 exec() 的替代方法。

不要将 exec 与函数名称一起使用,只需将函数对象保留在列表中即可:

fn_lst = [has_at, has_num, ...]

并直接执行调用:

def abc(xyz):
    for i in fn_lst:
        temp= i(xyz)
        print(temp)

首先,我们展示如何通过传递给 exec() 的字符串设置一个变量,该变量在调用 exec() 之外可用。然后我们展示一些示例,说明如何在调用 exec() 的函数调用之外使变量可用。

核心概念包括 exec() 作为参数、要执行的字符串以及用作全局和局部范围的两个字典。

例如,我们可以传递实际的全局和局部作用域,像这样:

exec( 'a = 3', globals(), locals() )

print( a )

这将打印以下结果:

3

但是,我们选择将哪些字典传递给 exec() 具有相当大的灵活性,这提供了几种方法来从调用 exec() 的函数中设置局部范围内的变量。

例如,我们可以将当前局部作用域传递给一个函数,然后将其用作 exec() 的局部字典,如下所示:

def demofunction( adict ):

    exec( 'a=1.', globals(), adict )

print( 'before calling the function' )
try:
    print( a )
except Exception as e:
    print( e )
    
demofunction( locals() )

print( 'after calling the function' )
print( 'a =', a )

这会打印:

before calling the function
name 'a' is not defined

after calling the function
a = 1.0

由于调用范围对于函数内部的范围是全局的,从函数内部设置局部变量的另一种简单方法是仅使用 globals() 作为 exec() 的第二个参数。

def demofunction( adict ):

    exec( 'a=1.', None, globals() )

print( 'before calling the function' )
try:
    print( a )
except Exception as e:
    print( e )
    
demofunction( locals() )

print( 'after calling the function' )
print( 'a =', a )

再次打印:

before calling the function
name 'a' is not defined

after calling the function
a = 1.0

因此,我们看到 exec() 实际上可以从函数内部在我们的本地范围内创建变量。

此外,您不限于 globals() 和 locals()。您可以将任何有效的字典传递给它。

def demofunction( adict ):

    exec( 'a=1.', None, adict )


somedict = { 'b': 1 }
print( somedict )
    
demofunction( somedict )

print( somedict )

现在输出是:

{'b': 1}
{'b': 1, 'a': 1.0}

注意:在第一个示例中,单独使用本地参数就足够了,即省略 globals()。两者都包含在这里以说明更一般的情况。您可以在 Python、Python Textbook - Scope

中阅读有关“Scope”的内容

我想提一下,之前在本主题中建议的许多“标准”答案在函数内部不起作用。例如,考虑以下代码片段:

def test():
    exec( 'a = 3', globals(), locals() )
    print(a)
test()

一切似乎都很好。但是,此代码在 Python 3:

中给出错误
NameError: name 'a' is not defined

我尝试了一些使用其他论坛中建议的 compile 函数的方法,但它们仍然对我不起作用(至少对于我提到的选项)。

根据我的研究,这是我见过的最接近工作的代码:

def test():
    lcls = locals()
    exec( 'a = 3', globals(), lcls )
    a = lcls["a"]
    print(f'a is {a}')
test()

成功打印:

a is 3

我认为这是一个总体上很重要的话题。有时,当您使用 Sympy 等符号代数库时,通过 exec 函数定义变量对于科学计算来说非常方便。

我希望有人知道这个问题的好答案。


编辑:

现在我很少用exec了。我已经意识到 OP 问题的 better/shorter 解决方案是使用 eval 函数简单地定义局部变量。 OP 的代码可以写成:

def abc(xyz):
    for i in fn_lst:
        temp = eval(i + '(xyz)')
        print (temp)
abc('avdfbafadnf')
# problem solved :)

由于变量名 temp 已经硬编码到函数中,使用 eval 不会改变解决方案的通用性。如果事先不知道变量的名称,eval 也可以按如下方式使用:

def advanced_eval(expr):
    var_names  = expr.split('=')[0].replace(' ','')
    rhs_values = eval('='.join(expr.split('=')[1:]))
    return var_names, rhs_values

如果定义 name,value = advanced_eval('a=3+3'),代码将有效地输出 name = 'a'value = 6

在这个问题上花了这么多时间进行命中和试验之后,我可以说像这样使用exec在函数内部没有任何问题,否则会抛出错误。 我已经对函数和变量进行了测试。

def main():
  x = "def y():\n\treturn('This will work')"
  #pass only globals() not locals()
  exec(x,globals())
  print(y())
  
main()

def test():
    #pass only globals() not locals()
    exec( 'a = 3', globals())
    print(a)
test()

这是在 W3School's online interpreter 上运行的屏幕截图(您可以 copy/paste 在这里自己测试)