简体   繁体   English

exec为什么不能在具有子功能的功能中工作?

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

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? 有人知道为什么这个Python代码不起作用吗? I get an error at the exec in test2. 我在test2中的exec处收到错误。 Also, I know exec's aren't good style, but trust me, I'm using exec for an appropriate reason. 另外,我知道exec的风格不好,但是请相信我,出于适当的原因,我正在使用exec。 I wouldn't use it otherwise. 否则我不会使用它。

#!/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关键字无关。

Correct. 正确。 You can't use exec in a function that has a subfunction, unless you specify a context. 除非指定上下文,否则不能在具有子功能的函数中使用exec。 From the docs: 从文档:

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. 如果在函数中使用了exec并且该函数包含带有自由变量的嵌套块,则除非exec显式指定exec的本地名称空间,否则编译器将引发SyntaxError。 (In other words, "exec obj" would be illegal, but "exec obj in ns" would be legal.) (换句话说,“ exec obj”将是非法的,但“ ns中的exec obj”将是合法的。)

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? 现在,下一个问题:为什么要使用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 :-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

Although in Python it looks kind of like the local variables are stored in a dictionary locals() , they usually aren't. 尽管在Python中看起来局部变量似乎存储在字典locals() ,但通常不是。 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. 如果使用locals()函数,则得到的是从所有局部变量创建的新字典,这就是为什么分配给locals()通常不起作用的原因。

There are a couple of exceptions to this scenario: 此方案有两个例外:

When you use an unqualified exec inside a function Python turns off the optimisation and uses a real dictionary for the local variables. 当您在函数内部使用不合格的exec Python会关闭优化功能,并为局部变量使用真正的字典。 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内部创建或更新变量,但这也意味着该函数中的所有局部变量访问将运行得更慢。

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来解决此问题,即使在这种情况下,您也不想使用任何作用域变量。

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 subfunction contains a free variable, and since in Python 2, exec could 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. 确实不起作用的原因是subfunction包含一个自由变量,并且由于在Python 2中, exec在理论上可以修改包含作用域中的局部变量,因此无法确定该变量是否应与全局变量绑定,父函数范围。 One of the verses in the Zen of Python is "In the face of ambiguity, refuse the temptation to guess." Python Zen中的其中一句诗是“面对模棱两可,拒绝猜测的诱惑”。 and this is what Python 2 does. 这就是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 None cannot be assigned to, and it is considered as a constant in the bytecode, the buggy parser thinks it is an unbound variable here. 即使无法将None赋值,并且在字节码中将其视为常量 ,但越野车解析器仍认为此处是未绑定的变量。

But if you replace it with 1 and 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, exec is just a simple function and isn't handled specially by the parser or the bytecode compiler. 在Python 3中, exec只是一个简单的函数,不会由解析器或字节码编译器专门处理。 In Python 3 exec cannot rebind function-local names, and thus this SyntaxError and ambiguity doesn't exist. 在Python 3中, exec无法重新绑定函数本地名称,因此此SyntaxError和歧义不存在。


One peculiar case in Python 2 vs 3 compatibility is that while Python 2.7 documentation states that Python 2 vs 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 . 形式exec(expr, globals)等同于exec expr in globals ,而形式exec(expr, globals, locals)等同于exec expr in globals, locals The tuple form of exec provides compatibility with Python 3, where exec is a function rather than a statement. exec的元组形式提供了与Python 3的兼容性,其中exec是函数而不是语句。

The tuple form has not always been 100 % compatible, as there was a bug in handling of exec in functions with nested functions (issue 21591) ; 元组形式并不总是100%兼容的,因为在处理带有嵌套函数的函数中exec存在错误(issue 21591) up to Python 2.7.8 the following code might have thrown an exception: 在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中修复,并且不再抛出。

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 ,我认为这不是错误。

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/

dict and list comprehensions may also be considered subfunctions on Python 2.7.5 dictlist理解也可能被视为Python 2.7.5的子函数

For example, this fails on Python 2.7.5, but works on Python 2.7.12: 例如,这在Python 2.7.5上失败,但在Python 2.7.12上有效:

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

with: 与:

  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

Likely it got internally compiled to a function in the bytecode. 它可能在内部被编译为字节码中的函数。

TODO find the fixing commit. TODO查找修复提交。 It was beyond my git log --grep foo. 这超出了我的git log --grep foo。

Analogous for dict comprehensions: 类似dict理解:

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

which is specially bad since it is a common parameter for the global argument. 这是特别糟糕的,因为它是global参数的通用参数。

Also raised at: https://github.com/sphinx-doc/sphinx/issues/5417#issuecomment-421731085 还提出了: https : //github.com/sphinx-doc/sphinx/issues/5417#issuecomment-421731085

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM