有没有办法让 locals() 和 globals() 像 defaultdict 一样
Is there are any way make locals() and globals() defaultdict-like
是否可以在运行时更改 Python 中 global
和 local
变量的行为?
在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 或其他东西。)
是否可以在运行时更改 Python 中 global
和 local
变量的行为?
在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 或其他东西。)