【问题标题】:Is there are any way make locals() and globals() defaultdict-like有什么方法可以让 locals() 和 globals() defaultdict-like
【发布时间】:2016-02-16 15:37:20
【问题描述】:

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

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

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

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

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

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

globals() 也有同样的问题。

【问题讨论】:

    标签: python variables python-internals locals


    【解决方案1】:

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

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

    请注意,NameError 会因缺少 全局变量 而引发异常,而不是局部变量。本地名称,如果尚未绑定,则改为抛出 UnboundLocalException。但是,您也不能用 defaultdict 替换 globals() 字典;模块对象的__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 之类的。)

      【讨论】:

        猜你喜欢
        • 2011-12-19
        • 2015-05-18
        • 1970-01-01
        • 2019-02-18
        • 2014-06-01
        • 2020-06-02
        • 1970-01-01
        • 2013-06-17
        • 2012-12-07
        相关资源
        最近更新 更多