我正在尝试理解Python的exec()函数

时间:2018-04-04 00:50:51

标签: python python-3.x

所以我有一个像

这样的函数的字符串
code = """def somefn(x):
    return x + x
    y = somefn(z)"""

我试图在另一个函数中运行它,比如

def otherfn(codestr):
    z = 2
    exec(codestr)
    return y

otherfn(code)

但它给了我错误:

  

追踪(最近一次通话):   文件“C:/Users/Admin/Desktop/heh.py”,第11行,in   otherfn(代码)   文件“C:/Users/Admin/Desktop/heh.py”,第9行,in otherfn   回来   NameError:名称'y'未定义

它在

之类的功能之外正常工作

z=2 exec(codestr) print(y)

它发现你很好但不确定为什么它在函数中时会出现问题。

我该如何解决这个问题?它与globals()和locals()有关吗?使用Python 3.6 btw。

1 个答案:

答案 0 :(得分:1)

您的代码存在一些问题。首先,你有一个缩进问题 - 在import foo.bar foo.bar.my_method() 函数中y获得'定义',在somefn()之后,所以它实际上从来没有机会进入堆栈。您需要将return重新定义为:

code

但这只是冰山一角。更大的问题是code = """def somefn(x): return x + x y = somefn(z)""" 无法修改函数的本地范围。这是因为Python不使用exec()来查找本地范围内的变量,因此来自dict的所有更改都不会反映回堆栈以启用查找。这会导致奇怪的问题,其中exec()似乎更改了exec()字典,但Python仍然会抛出locals()

NameError

这是一种预期的行为,如issue4831中所述,并在official docs进一步表述:

  

注意:默认的 locals 的行为与下面的函数locals()相同:对默认 locals 字典的修改不应该是尝试。如果您需要在函数exec()返回后查看代码对 locals 的影响,请传递显式的 locals 字典。

但是如果你必须反映这些变化,你可以做一个post-exec本地范围更新:

def otherfn(codestr):
    z = 2
    exec(codestr)
    print(locals()["y"])  # prints 4
    return y  # NameError

otherfn(code)