【问题标题】:subclassed python dictionary for custom namespace in exec() methodexec() 方法中自定义命名空间的子类化 python 字典
【发布时间】:2012-08-29 19:25:26
【问题描述】:

我正在尝试对字典进行子类化以在 exec 方法中使用。 最终,我希望本地函数具有自定义名称范围行为。

在下面的代码中,函数b() 实际上确实有正确的globals() 字典可供它使用,但是在解析z 时它无法搜索它。

函数b()是否首先不搜索locals()然后globals()

非常令人费解。 任何帮助表示赞赏。

t = '''
def b():
#   return (globals()['z']) #works
    return z #fails

b()
'''

class MyDict(dict):
    def __init__(self, g):
        dict.__init__(self)
        self.my_g = g


    def __getitem__(self, key):
        print("GET ", key)
        try:
            val = dict.__getitem__(self, key)
        except:
            print("GET exception1")
            val = self.my_g[key]
        return val


g = {'z':123}

md = MyDict(g)

#fails to find z
exec(t, md, md)

#works
#exec(t, g, g)

输出

GET  b
Traceback (most recent call last):
  File "/project1/text12", line 31, in <module>
  File "<string>", line 6, in <module>
  File "<string>", line 4, in b
NameError: global name 'z' is not defined

【问题讨论】:

  • 返回 z 失败,因为没有变量 z。你说 return (globals()['z']) 有效,你想在返回 z 的时候完成什么?
  • 我希望 z 从传入的全局字典中解析为在下面的答案中工作。干杯

标签: python dictionary namespaces exec subclass


【解决方案1】:

在 python 3.3 之前,您不能为 exec 语句的 globals 值使用自定义 dict 子类。执行编译代码的底层 C 代码直接访问底层 C 结构,忽略您可能已经实现的任何自定义挂钩。

换句话说,当代码执行LOAD_GLOBAL 操作时(就像函数z 中的b 一样),C 字节码评估循环使用当前帧访问globals 结构C API,绕过任何 python 覆盖。

这在exec() function documentation 中记录为:

如果只提供globals,它必须是一个字典,它将用于全局和局部变量。如果给出了 globalslocals,则它们分别用于全局和局部变量。如果提供,locals 可以是任何映射对象。

此限制在 Python 3.3 中已放宽,请参阅 issue 14385。文档尚未更新,但字节码评估循环已更新,可在回退到 C API 访问之前测试自定义映射。如果使用自定义映射,则使用PyObject_GetItem 函数,该函数将在自定义类上调用__getitem__

【讨论】:

  • 非常感谢。我还没有机会将它重新用于我原来的工作,但它看起来很棒。再次感谢-Rob
  • 对不起@martijn-pieters,它还没有。您的添加适用于在本地范围内查找变量,但不像原始示例那样在函数范围内查找变量。如果相关的话,我也在使用 Python 3.2。换句话说: t = 'print(z)' 现在可以工作,但是: t = ''' def b(): return z b() ''' 仍然失败。关于在这种情况下如何获取函数范围以搜索全局字典的任何见解,就像我直接传入 g 时一样?谢谢。
  • @rbairos:这就是我在前半部分的解释;函数作用域中的未绑定变量总是在下一个global() 作用域中查找。这里没有模块本地范围,通常也将东西放在 global() 范围内。
  • 但是,@martijn-pieters 不是我作为参数传入 exec() 的字典的 global() 范围吗? IE。执行(t,md,md)?对为什么它不尝试搜索 md 感到困惑,因为它在我调用 (t,g,g) 时搜索 g ? (对不起,这种微妙之处对我来说是新的)
  • @rbairos:调查一下 python 3 是否有所作为。
猜你喜欢
  • 1970-01-01
  • 2013-05-17
  • 1970-01-01
  • 2021-12-29
  • 2014-06-20
  • 1970-01-01
  • 2022-06-17
  • 2014-03-24
  • 2020-03-30
相关资源
最近更新 更多