为什么exec不能在带有子功能的函数中工作?

时间:2010-12-19 20:13:01

标签: python exec

看起来你不能在具有子功能的函数中使用exec ......

任何人都知道为什么这个Python代码不起作用?我在test2的exec上遇到错误。另外,我知道exec的风格并不好,但相信我,我正在使用exec是出于正当的理由。否则我不会用它。

#!/usr/bin/env python
#

def test1():
    exec('print "hi from test1"')

test1()

def test2():
    """Test with a subfunction."""
    exec('print "hi from test2"')
    def subfunction():
        return True

test2()

编辑:我将错误缩小到在子功能中使用功能。它与raise关键字无关。

6 个答案:

答案 0 :(得分:65)

正确。除非指定上下文,否则不能在具有子函数的函数中使用exec。来自文档:

  

如果exec用于函数和   function包含一个嵌套块   自由变量,编译器会   除非执行exec,否则引发一个SyntaxError   显式指定本地   exec的命名空间。 (其他   单词,“exec obj”将是非法的,   但是“ns中的exec obj”是合法的。)

如果不是星期天晚上,我很可能会理解这一点。 现在,下一个问题:你为什么使用exec?这很少需要。你说你有充分的理由。我对此持怀疑态度。 ;)如果你有充分的理由我会告诉你解决方法。 :-P

哦,好吧,无论如何:

def test2():
    """Test with a subfunction."""
    exec 'print "hi from test2"' in globals(), locals()
    def subfunction():
        return True

答案 1 :(得分:28)

虽然在Python中看起来有点像局部变量存储在字典locals()中,但它们通常不是。相反,它们主要存储在堆栈中并通过索引访问。这使得局部变量查找比每次都必须进行字典查找更快。如果您使用locals()函数,那么您获得的是从所有局部变量创建的新字典,这就是分配给locals()通常不起作用的原因。

这种情况有几个例外:

当您在函数中使用非限定exec时,Python会关闭优化并使用真实字典作为局部变量。这意味着您可以从exec内部创建或更新变量,但这也意味着该函数中的所有本地变量访问都将运行得更慢。

另一个例外是,当您嵌套函数时,内部函数可以访问外部函数作用域中的局部变量。当它执行此操作时,变量存储在“单元”对象中,而不是存储在堆栈中。除了从内部或外部函数访问它们之外,额外的间接级别使得所有范围变量的使用都变慢。

您遇到的问题是,通常存储局部变量的这两个例外是不兼容的。您不能将变量存储在字典中并同时通过单元格引用进行访问。 Python 2.x通过禁止exec来解决这个问题,即使在这样的情况下你也不会尝试使用任何作用域变量。

答案 2 :(得分:6)

这是一个相当有趣的案例:

>>> def func():
...     exec('print "hi from func"')
...     def subfunction():
...         return True
... 
  File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'func' because 
it contains a nested function with free variables

这不起作用的原因是subfunction包含一个自由变量,因为在Python 2中,exec理论上可以修改包含范围内的本地,它将是无法确定变量是否应该从全局或父函数范围绑定。 Python中的一个经文就是&#34;面对歧义,拒绝猜测的诱惑。&#34; 这就是Python 2所做的。

现在的问题是:这个免费(未绑定)变量是什么?好吧,它是True

确实可以使用None重现:

>>> def func():
...     exec('print "hi from func"')
...     def subfunction():
...         return None
... 
  File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'test2' because it contains a nested
function with free variables

即使None无法分配给它,并且在字节码中它被视为常量,但是错误的解析器认为它是一个未绑定的变量。

但是如果你用1替换它并且它没有问题:

>>> def test2():
...     exec('print "hi from func"')
...     def subfunction():
...         return 1
... 
>>>

要避免此错误,请明确指定exec要使用的全局变量和可能的本地变量,例如:

>>> def test2():
...     exec 'print "hi from test2"' in {}
...     def subfunction():
...         return None
...
>>>

在Python 3中,exec只是一个简单的函数,并不是由解析器或字节码编译器专门处理的。在Python 3中exec不能重新绑定函数本地名称,因此这种SyntaxError和歧义不存在。

Python 2与3兼容性中的一个特殊情况是Python 2.7 documentation表示

  

表单exec(expr, globals)相当于exec expr in globals,而表单exec(expr, globals, locals)相当于exec expr in globals, localsexec的元组形式提供与Python 3的兼容性,其中exec是函数而不是语句。

元组表格并不总是100%兼容,因为有a bug in handling of exec in functions with nested functions (issue 21591);直到Python 2.7.8,以下代码可能抛出异常:

def func():
    exec('print "hi from test2"', {})
    def subfunction():
        return None

这在Python 2.7.9中修复,不再抛出。

答案 3 :(得分:4)

在修改print语句以使用print函数后,在Python 3.1.3中运行良好。

在Python 2.6中,它产生SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables,我认为这不是一个错误。

答案 4 :(得分:1)

这个错误对我来说似乎很明显:

SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables

有关详细信息,请参阅第227页:http://www.python.org/dev/peps/pep-0227/

答案 5 :(得分:1)

dictlist的理解也可以被视为Python 2.7.5上的子功能

例如,这在Python 2.7.5上失败,但在Python 2.7.12上有效:

def func():
    exec('print("a")')
    (str(e) for e in range(10))

具有:

  File "./a.py", line 4
    exec('print("a")')
SyntaxError: unqualified exec is not allowed in function 'func' it contains a nested function with free variables

很可能它已在内部编译为字节码中的函数。

TODO查找修复提交。这超出了我的git log --grep foo。

类似于dict的理解:

def func():
    exec('print("a")', {e:str(e) for e in range(10)})

这是特别糟糕的,因为它是global参数的通用参数。

也在https://github.com/sphinx-doc/sphinx/issues/5417#issuecomment-421731085

处提出