2

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

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

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

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

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

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

同样的问题也适用globals()

4

2 回答 2

4

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

出于性能原因,实际的命名空间是一个数组,并且本地不是按名称而是按索引查找的。事后您不能为此添加新名称,因为编译器根本没有考虑到数组中的更多引用。

请注意,缺少全局变量NameError会引发异常,而不是本地变量。本地名称,如果尚未绑定,则改为抛出一个。但是,您也不能用defaultdict 替换字典;模块对象的属性是只读的。即使它不是只读的,由于在命名空间中查找名称的方式,仅支持内置类型;这是设计使然UnboundLocalExceptionglobals()__dict__dict

于 2016-02-16T15:39:36.247 回答
2

是的,有点,使用元类class,Python 用于修改语句行为的工具。

在这里,从其方法DefaultDictMeta返回一个实例。因此,任何具有元类的类最终都会为其命名空间使用 的实例。这意味着名称查找在.defaultdict__prepare__DefaultDictMetadefaultdictNoNameErrorsInBody

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 什么的。)

于 2016-02-16T15:48:18.820 回答