带有自定义字典的Eval()在CPython中不起作用

时间:2019-03-04 17:19:51

标签: python cpython

我正在尝试使用自定义字典作为全局变量来运行某些表达式。

class Namespace(dict):
    def __getitem__(self, key):
        if key == "y":
            return 10
        else:
            return super(Namespace, self).__getitem__(key)

def run_with_dict(d):
    print(eval("x + y", d))
    print(eval("[ (p * y) for p in ['foo', 'bar'] ]", d))
    print(eval("{ p: (p * y) for p in ['foo', 'bar'] }", d))

custom = Namespace()
custom["x"] = 2
regular = {"x": 2, "y": 10}

run_with_dict(regular)
run_with_dict(custom)

在CPython 2.7中运行它时,它仅在对地图的理解上失败:

12
['foofoofoofoofoofoofoofoofoofoo', 'barbarbarbarbarbarbarbarbarbar']
{'foo': 'foofoofoofoofoofoofoofoofoofoo', 'bar': 'barbarbarbarbarbarbarbarbarbar'}
12
['foofoofoofoofoofoofoofoofoofoo', 'barbarbarbarbarbarbarbarbarbar']
Traceback (most recent call last):
  File "<stdin>", line 22, in <module>
  File "<stdin>", line 15, in run_with_dict
  File "<string>", line 1, in <module>
  File "<string>", line 1, in <dictcomp>
NameError: global name 'y' is not defined

但是当它与PyPy 2.7一起运行时,它可以正常工作。在任何Python 3中也可以正常工作。

什么实现差异可以解释这一点?这是CPython 2.7中的错误还是未定义的行为?我有什么办法可以使其在两种实现中都能正常工作?

1 个答案:

答案 0 :(得分:2)

CPython通常采用快捷方式。 CPython 2.7中的dict理解期望dict完全是dict而不是其子类。它不会打扰您覆盖的__getitem__方法;对于dict.__getitem__来说是直接的,当然看不到名称为y的条目。

我不确定这是否是未定义的行为,但是在python 3中进行了更改的事实意味着这是一个错误。