How to convert this Python 2.7 code to Python 3?

wim*_*wim 5 python cpython local-variables python-2.7 python-3.x

The following code works in Python 2.7, to dynamically inject local variables into a function scope:

myvars = {"var": 123}

def func():
    exec("")
    locals().update(myvars)
    print(var)

func()
# assert "var" not in globals()
Run Code Online (Sandbox Code Playgroud)

这有点微妙,但是exec语句的存在向编译器指示可以修改本地名称空间。在参考实现中,它将把名称“ locals”的查找从LOAD_GLOBAL op转换为LOAD_NAME op,从而允许添加到本地名称空间。

在Python 3中,它exec变成了函数而不是语句,并且该locals()调用返回了名称空间的副本,其中的修改无效。

您如何在Python 3中重新创建想法,以便在函数内部动态创建局部变量?还是仅在Python 2.x中才有“功能”?

注意:该代码不得在外部范围内绑定名称。

use*_*ica 1

我不推荐它,但你可以将函数的主体放在类语句中:

myvars = {"var": 123}

def func():
    class Bleh:
        locals().update(myvars)
        print(var)

func()
Run Code Online (Sandbox Code Playgroud)

与 Python 2 代码一样,在这种情况下修改工作的事实locals()在技术上没有记录,并且可能会发生变化。类作用域必须使用实际的字典进行局部变量解析,但理论上,稍后的 Python 实现可能会复制该字典locals()或类似的内容。

与 Python 2 代码一样,这样做会干扰闭包变量解析,包括如下微妙情况:

myvars = {"var": 123}

def func():
    class Bleh:
        locals().update(myvars)
        print([var for x in (1, 2, 3)])

func()
Run Code Online (Sandbox Code Playgroud)

甚至

def func():
    class Bleh:
        var = 123
        print([var for x in (1, 2, 3)])

func()
Run Code Online (Sandbox Code Playgroud)

这两种情况都会导致 NameError,因为列表推导式创建了一个无法访问var.

在 Python 2 中,尝试使用闭包变量 withexec会导致语法错误。如果您尝试使用类语句复制 Python 3 中的功能,则不会得到任何此类检测。

最后,Python在类语句完成后尝试构建一个类,这可能会导致奇怪的问题,例如__set_name__方法意外运行。您至少可以通过使用元类来解决此问题:

class NoClass(type):
    def __new__(self, *args, **kwargs):
        return None

def func():
    class Bleh(metaclass=NoClass):
        ...
Run Code Online (Sandbox Code Playgroud)