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

53 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()
Run Code Online (Sandbox Code Playgroud)

编辑:我把bug缩小到在子功能中有一个功能.它与raise关键字无关.

Len*_*bro 65

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

如果在函数中使用exec并且函数包含带有自由变量的嵌套块,则编译器将引发SyntaxError,除非exec显式指定了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
Run Code Online (Sandbox Code Playgroud)


Dun*_*can 28

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

这种情况有几个例外:

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

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

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


Ant*_*ala 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
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是subfunction包含一个自由变量,并且因为在Python 2中,exec理论上可以修改包含范围中的局部变量,所以无法确定变量是否应该从全局变量或父变量绑定功能范围."禅宗禅"中的一句经文是"面对模棱两可,拒绝猜测的诱惑." 这就是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
Run Code Online (Sandbox Code Playgroud)

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

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

>>> def test2():
...     exec('print "hi from func"')
...     def subfunction():
...         return 1
... 
>>>
Run Code Online (Sandbox Code Playgroud)

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

>>> def test2():
...     exec 'print "hi from test2"' in {}
...     def subfunction():
...         return None
...
>>>
Run Code Online (Sandbox Code Playgroud)

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


Python 2与3兼容性的一个特殊情况是,虽然Python 2.7文档说明了这一点

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

元组表单并不总是100%兼容,因为在处理exec具有嵌套函数的函数时存在错误(issue 21591) ; 直到Python 2.7.8,以下代码可能抛出异常:

def func():
    exec('print "hi from test2"', {})
    def subfunction():
        return None
Run Code Online (Sandbox Code Playgroud)

这是在Python 2.7.9中修复的,它不再抛出.