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

wsewodh2  于 2023-05-13  发布在  Python
关注(0)|答案(6)|浏览(178)

我试图运行这段代码,但似乎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()的替代方案。

ibrsph3r

ibrsph3r1#

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

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问题的一个更好/更短的解决方案是使用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

vaj7vani

vaj7vani2#

首先,我们展示了如何使传递给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 Textbook - Scope中阅读Python中的“Scope”

qf9go6mv

qf9go6mv3#

在花了这么多时间在这个问题上做了大量的尝试之后,我可以说像这样使用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上运行的屏幕截图(您可以复制/粘贴并在这里自己测试)x1c 0d1x

vvppvyoh

vvppvyoh4#

不使用带有函数名的exec,只需将函数对象保留在列表中:

fn_lst = [has_at, has_num, ...]

并执行调用 * 直接 *:

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

snz8szmq5#

我搜索这个问题是因为我试图将配置文件的变量导入到函数中,但失败了。
经过试验,我得出以下结论:

  1. globals()['a']=1可以改变全局变量。
  2. locals()['a']=1不能更改当前作用域中的局部变量,除非当前作用域是“main”,其中id(locals())==id(globals())。
    这就是为什么局部变量的exec()在“main”作用域中工作,但在函数内部不工作。
    我认为这是python作用域机制的一个陷阱。
irlmq6kh

irlmq6kh6#

Q:如何在for循环中运行exec

A:循环前获取命名空间。

Exec使用一个命名空间来运行,当您在循环中运行它时,该命名空间显然会发生变化。因此

L = locals()
[exec(s, L) for s in ['x=1']]

可以工作,但是,如果没有给出Lexec将执行命令,因此它们在本地命名空间中不可用。

相关问题