是否可以在运行时更改Python中local
和dict
变量的行为?
在Python中,locals()
提供对当前执行范围中的变量的引用,该变量是>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
对象。
locals()
是否可以将locals()
返回的引用替换为defaultdict
,但在替换之前保留以前的值(UnboundLocalException
的副本)?
我希望在使用未初始化的变量并访问执行范围中的任何变量名时避免locals()
异常(未初始化的变量将采用指定的默认值)。
我试图修改java -cp zookeeper.jar:lib/log4j-1.2.15.jar:conf \ org.apache.zookeeper.server.quorum.QuorumPeerMain zoo.cfg
返回的值,将其重新分配给当地人,但没有成功。
同样的问题适用于globals()
。
答案 0 :(得分:4)
不,你不能。 locals()
只是用于函数的实际命名空间的反射。
出于性能原因,实际的命名空间是数组,并且不会按名称而是按索引查找本地。事后,您无法为此添加新名称,因为编译器根本没有考虑数组中的更多引用。
请注意,对于缺少全局而不是本地人,会抛出NameError
个异常。本地名称,如果尚未绑定,则抛出UnboundLocalException
。但是,您无法使用defaultdict替换globals()
字典;模块对象的__dict__
属性是只读的。即使它不是只读的,也只支持内置的dict
类型,因为在命名空间中查找名称的方式;这是by design。
答案 1 :(得分:2)
是的,使用metaclasses Python工具来修改class
语句的行为。
此处,DefaultDictMeta
从defaultdict
方法返回__prepare__
的实例。因此,具有DefaultDictMeta
元类的任何类将最终使用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还是什么。)