pau*_*are 2 python dictionary subclass
我正在对一个字典进行子类化,并且希望获得一些帮助来理解下面的行为(请)[Python 版本:3.11.3]:
class Xdict(dict):
def __init__(self, d):
super().__init__(d)
self._x = {k: f"x{v}" for k, v in d.items()}
def __getitem__(self, key):
print("in __getitem__")
return self._x[key]
def __str__(self):
return str(self._x)
def __iter__(self):
print("in __iter__")
d = Xdict({"a": 1, "b": 2})
print(d)
print(dict(d))
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
{'a': 'x1', 'b': 'x2'}
in __getitem__
in __getitem__
{'a': 'x1', 'b': 'x2'}
Run Code Online (Sandbox Code Playgroud)
如果我注释掉该__iter__方法,输出会像这样改变:
{'a': 'x1', 'b': 'x2'}
{'a': 1, 'b': 2}
Run Code Online (Sandbox Code Playgroud)
显然该__iter__方法没有被调用,但它的存在正在影响行为。
我只是对为什么会发生这种情况感兴趣。我并不是在寻找替代解决方案来防止它。
谢谢,保罗。
Python 的内部经常直接调用内置类功能的 C 级实现,即使子类可能覆盖了该功能,这会导致许多奇怪的错误,其中方法覆盖不会在您期望的地方被调用是。
许多实现都是这种情况dict,但是当字典在 Python 3.6 中成为保留顺序时,标准库中就会出现这些错误之一x:当是 OrderedDict 时,dict(x)将复制底层dict实现的顺序,而不是OrderedDict顺序(即单独跟踪)。
为了修复这个错误,他们在代码中添加了一个检查,dict_merge来决定是否使用快速路径:
if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) {
Run Code Online (Sandbox Code Playgroud)
dict_merge是负责将另一个映射的内容复制到字典中的底层例程。以前,这一行只是说if (PyDict_Check(b)) {,如果其他映射是任何 dict 实例,它将使用快速路径。现在,它还检查实例是否没有覆盖的__iter__.
如果实例有一个被覆盖的__iter__,dict_merge将使用慢速路径,因此您看到了差异。然而,慢速路径实际上并不使用 __iter__. 它使用keys,这就是为什么即使您__iter__不返回迭代器,您的代码也能工作。
| 归档时间: |
|
| 查看次数: |
105 次 |
| 最近记录: |