用于exec()方法中自定义命名空间的子类python字典

时间:2012-08-29 19:25:27

标签: python dictionary namespaces exec subclass

我正在尝试将字典子类化以用于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

1 个答案:

答案 0 :(得分:4)

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

换句话说,当代码执行LOAD_GLOBAL操作时(如函数zb的情况),C字节码评估循环访问globals使用C API在当前帧中构造,绕过任何python覆盖。

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

  

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

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