2016-02-16 49 views
2

是否有可能在运行时更改Python中globallocal变量的行为?是否有任何方式使本地()和全局变量()defaultdict样

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

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

是否有可能取代它之前,以取代locals()返回到defaultdict是参考,但保留以前的值(locals()复印件)?

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

我试图修改由locals()返回的值,将其重新分配给当地人而没有成功。

同样的问题是globals()

回答

4

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

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

请注意,NameError例外情况是因为丢失全局变量,而非当地人。本地名称如果尚未绑定,则会抛出UnboundLocalException。但是,您不能用字典替换defaultdict,但是;模块对象的__dict__属性是只读的。即使它不是只读的,由于在名称空间中查找名称的方式,只支持内置的dict类型;这是by design

2

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

这里,DefaultDictMeta从其__prepare__方法返回defaultdict的实例。因此,元类为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或其他东西一样。)