如何将此 Python 2.7 代码转换为 Python 3?

How to convert this Python 2.7 code to Python 3?

以下代码适用于 Python 2.7,可将局部变量动态注入函数范围:

myvars = {"var": 123}

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

func()
# assert "var" not in globals()

这有点微妙,但是 exec 语句的存在向编译器表明局部命名空间可能被修改。在参考实现中,它将名称 "locals" 的查找从 LOAD_GLOBAL op 转换为 LOAD_NAME op,从而能够添加到本地命名空间。

在Python3中,exec变成函数而不是语句,而locals()调用returns命名空间的副本,其中修改没有效果。

如何重现 Python 3 中的想法,在函数内动态创建局部变量?或者这是 "feature" 只有 Python 2.x 才有可能吗?

注意:代码不得绑定外部作用域中的名称。

我不推荐它,但您可以将函数体放在 class 语句中:

myvars = {"var": 123}

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

func()

与 Python 2 代码一样,修改 locals() 在这种情况下起作用的事实在技术上没有记录并且可能会更改。 class 范围必须使用实际的字典来解析局部变量,但理论上,稍后的 Python 实现可能会复制该字典用于 locals() 或类似的东西。

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

myvars = {"var": 123}

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

func()

甚至

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

func()

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

的新范围

在 Python 2 中,尝试将闭包变量与 exec 一起使用会导致 SyntaxError。如果您尝试使用 class 语句复制 Python 3 中的功能,您不会得到任何此类检测。

最后,Python 尝试在 class 语句完成后构建一个 class,这可能会导致一些奇怪的问题意外地喜欢 __set_name__ 方法 运行。您至少可以通过使用 metaclass:

来解决这个问题
class NoClass(type):
    def __new__(self, *args, **kwargs):
        return None

def func():
    class Bleh(metaclass=NoClass):
        ...