有没有办法让 locals() 和 globals() 像 defaultdict 一样

Is there are any way make locals() and globals() defaultdict-like

是否可以在运行时更改 Python 中 globallocal 变量的行为?

在Python中,locals()给出了对当前执行范围内变量的引用,是一个dict对象。

>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}

是否可以将 locals() 返回的引用替换为 defaultdict,但在替换之前保留之前的值(locals() 的副本)?

我希望这可以避免 UnboundLocalException 使用未初始化的变量并访问执行范围内的任何变量名时的异常(未初始化的变量将采用指定的默认值)。

我试图通过将 locals() 返回的值重新分配给本地人来修改它,但没有成功。

同样的问题也适用于 globals()

不,你不能。 locals() 只是用于函数的实际命名空间的 反映

出于性能原因,实际命名空间是一个 array 并且局部变量不是按名称而是按索引查找的。你不能在事后向它添加新名称,因为编译器根本没有考虑数组中的更多引用。

请注意 NameError 异常会因缺少 globals 而不是局部变量而抛出。本地名称,如果尚未绑定,则抛出一个 UnboundLocalException。但是,您也不能用 defaultdict 替换 globals() 字典;模块对象的 __dict__ 属性是只读的。即使它不是只读的,由于在名称空间中查找名称的方式,也只支持内置的 dict 类型;这是 by design.

是的,有点,使用 metaclasses、Python 的工具来修改 class 语句的行为。

此处,DefaultDictMeta returns 来自其 __prepare__ 方法的 defaultdict 的一个实例。因此,任何具有 DefaultDictMeta 的 metaclass 的 class 将最终使用 defaultdict 的实例作为其命名空间。这意味着在 NoNameErrorsInBody.

的正文中名称查找 不会失败
from collections import defaultdict

class DefaultDictMeta(type):
    def __prepare__(name, bases, default=None, **kwargs):
        return defaultdict(lambda: default)

    def __new__(meta, name, bases, dct, **kwargs):
        # swallow keyword arguments
        return super().__new__(meta, name, bases, dct)

    def __init__(cls, name, bases, dct, **kwargs):
        # swallow keyword arguments
        pass

class NoNameErrorsInBody(metaclass=DefaultDictMeta, default=2):
    x = y + 3  # y is not defined


>>> NoNameErrorsInBody.x
5

不言而喻,您永远不应该在实际代码中这样做。我只是为了一点乐趣而演示它。 (想象一下,当您使用无效的名称时,尝试调试不告诉您的代码。这会很糟糕,例如,我不知道,Javascript 或其他东西。)