Python 为什么 exec 在带有子函数的函数中不起作用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4484872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 15:57:43  来源:igfitidea点击:

Why doesn't exec work in a function with a subfunction?

pythonexec

提问by

It looks like you can't use exec in a function that has a subfunction...

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

Anyone know why this Python code doesn't work? I get an error at the exec in test2. Also, I know exec's aren't good style, but trust me, I'm using exec for an appropriate reason. I wouldn't use it otherwise.

有人知道为什么这个 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()

EDIT: I narrowed down the bug to having a function in a subfunction. It has nothing to do with the raise keyword.

编辑:我将错误范围缩小到在子函数中有一个函数。它与 raise 关键字无关。

采纳答案by Lennart Regebro

Correct. You can't use exec in a function that has a subfunction, unless you specify a context. From the docs:

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

If exec is used in a function and the function contains a nested block with free variables, the compiler will raise a SyntaxError unless the exec explicitly specifies the local namespace for the exec. (In other words, "exec obj" would be illegal, but "exec obj in ns" would be legal.)

如果在函数中使用 exec 并且该函数包含带有自由变量的嵌套块,则编译器将引发 SyntaxError 除非 exec 明确指定 exec 的本地命名空间。(换句话说,“exec obj”是非法的,但“exec obj in ns”是合法的。)

There is good reason for this which I would probably understand if it wasn't Sunday night. Now, next question: Why are you using exec? It's very rarely needed. You say you have a good reason. I'm feeling sceptical about that. ;) If you have a good reason I'll tell you the workaround. :-P

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

Oh well, here it is anyway:

哦,好吧,无论如何,这里是:

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

回答by Wolph

The error seems to be fairly obvious to me:

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

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

See pep 227 for more info: http://www.python.org/dev/peps/pep-0227/

有关更多信息,请参阅 pep 227:http: //www.python.org/dev/peps/pep-0227/

回答by Lie Ryan

That works well in Python 3.1.3, after modifying the print statement to use print function.

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

In Python 2.6, it produces SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables, I don't think it's a bug.

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

回答by Duncan

Although in Python it looks kind of like the local variables are stored in a dictionary locals(), they usually aren't. Instead they are mostly stored on the stack and accessed by index. This makes local variable lookup faster than if it had to do a dictionary lookup every time. If you use the locals()function then what you get is a fresh dictionary created from all the local variables, and that's why assigning to locals()doesn't generally work.

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

There are a couple of exceptions to this scenario:

这种情况有几个例外:

When you use an unqualified execinside a function Python turns off the optimisation and uses a real dictionary for the local variables. That means you can create or update variables from inside the exec, but it also means all local variable access in that function will run more slowly.

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

The other exception is that when you nest functions the inner function can access local variables in the outer function scope. When it does this the variable is stored in a 'cell' object instead of being stored on the stack. The extra level of indirection makes all use of scoped variables slower whether you access them from the inner or outer function.

另一个例外是,当您嵌套函数时,内部函数可以访问外部函数作用域中的局部变量。当它这样做时,变量存储在“单元”对象中,而不是存储在堆栈中。无论您是从内部函数还是外部函数访问它们,额外的间接级别都会使所有作用域变量的使用速度变慢。

The catch that you've encountered is that these two exceptions to how local variables are normally stored are incompatible. You cannot have a variable stored in a dictionary and accessed through a cell reference at the same time. Python 2.x fixes this by disallowing the exec, even in cases like this where you aren't trying to use any scoped variables.

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

回答by Antti Haapala

This is a rather interesting case:

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

>>> 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

The reason why this doesn't work indeed is that subfunctioncontains a free variable, and since in Python 2, execcould theoretically modify the locals in the containing scope, it would be impossible to decide if the variable should be bound from the global or the parent function scope. One of the verses in the Zen of Python is "In the face of ambiguity, refuse the temptation to guess."and this is what Python 2 does.

这确实不起作用的原因是它subfunction包含一个自由变量,并且由于在 Python 2 中,exec理论上可以修改包含范围内的局部变量,因此无法决定变量是应该从全局绑定还是从父变量绑定功能范围。巨蟒之禅》中的一首诗是“面对歧义,拒绝猜测的诱惑”。这就是 Python 2 所做的。

Now the question is: what is this free (unbound) variable? Well, it is True!

现在的问题是:这个自由(未绑定)变量是什么?嗯,是的True

Indeed it is reproduceable with None:

事实上,它是可复制的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

Even though Nonecannot be assigned to, and it is considered as a constantin the bytecode, the buggy parser thinks it is an unbound variable here.

即使None不能被赋值,并且在字节码中它被认为是一个常量,但有问题的解析器认为它在这里是一个未绑定的变量。

But if you replace it with 1and it works without problems:

但是,如果您将其替换为1并且它可以正常工作:

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

To avoid this error, specify explicitly the globals and possibly locals that are to be used by exec, say:

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

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


In Python 3, execis just a simple function and isn't handled specially by the parser or the bytecode compiler. In Python 3 execcannot rebind function-local names, and thus this SyntaxError and ambiguity doesn't exist.

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



One peculiar case in Python 2 vs 3 compatibility is that while Python 2.7 documentationstates that

Python 2 与 3 兼容性的一个特殊情况是,虽然Python 2.7 文档指出

The form exec(expr, globals)is equivalent to exec expr in globals, while the form exec(expr, globals, locals)is equivalent to exec expr in globals, locals. The tuple form of execprovides compatibility with Python 3, where execis a function rather than a statement.

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

The tuple form has not always been 100 % compatible, as there was a bug in handling of execin functions with nested functions (issue 21591); up to Python 2.7.8 the following code might have thrown an exception:

元组形式并不总是 100% 兼容,因为在处理exec具有嵌套函数的函数时存在错误(issue 21591);在 Python 2.7.8 之前,以下代码可能会引发异常:

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

This was fixed in Python 2.7.9 and it no longer throws.

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