当从dict导出时,重载__iter__被绕过 [英] overloaded __iter__ is bypassed when deriving from dict
问题描述
尝试创建自定义不区分大小写的字典,我遇到了以下不方便(从我的观点)意外的行为。如果从 dict
导出类,则重载的 __ iter __
, keys
值
函数在转换回 dict
时将被忽略。我已将其精简到以下测试用例:
Trying to create a custom case-insensitive dictionary, I came the following inconvenient and (from my point-of-view) unexpected behaviour. If deriving a class from dict
, the overloaded __iter__
, keys
, values
functions are ignored when converting back to dict
. I have condensed it to the following test case:
import collections
class Dict(dict):
def __init__(self):
super(Dict, self).__init__(x = 1)
def __getitem__(self, key):
return 2
def values(self):
return 3
def __iter__(self):
yield 'y'
def keys(self):
return 'z'
if hasattr(collections.MutableMapping, 'items'):
items = collections.MutableMapping.items
if hasattr(collections.MutableMapping, 'iteritems'):
iteritems = collections.MutableMapping.iteritems
d = Dict()
print(dict(d)) # {'x': 1}
print(dict(d.items())) # {'y': 2}
键的值
,值
和 __ iter __
, __ getitem __
只是为了演示哪些方法不一致实际上被调用。
The values for keys
,values
and __iter__
,__getitem__
are inconsistent only for demonstration which methods are actually called.
如果给定了一个位置参数,它是一个映射对象,则创建一个
字典与映射
对象相同的键值对。否则,位置参数必须是一个迭代器对象。
If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterator object.
我想这与第一个句子有关,也可能是优化内置字典。
I guess it has something to do with the first sentence and maybe with optimizations for builtin dictionaries.
为什么调用 dict(d)
不使用任何 key
, __ iter __
?
可以通过某种方式重载映射来强制 dict
构造函数来使用我的键值对的演示?
Why exactly does the call to dict(d)
not use any of keys
, __iter__
?
Is it possible to overload the 'mapping' somehow to force the dict
constructor to use my presentation of key-value pairs?
为什么我用这个?对于不区分大小写但保留字典的字典,我想在内部:
Why did I use this? For a case-insensitive but -preserving dictionary, I wanted to:
- store(lowercase =>(original_case,value)显示为(any_case =>值)。
- 派生自
dict
,以便使用使用isinstance $ c $的一些外部库代码c>检查
- 不使用2个字典查找:lower_case => original_case,其次是original_case => value(这是我现在正在做的解决方案)
- store (lowercase => (original_case, value)) internally, while appearing as (any_case => value).
- derive from
dict
in order to work with some external library code that usesisinstance
checks - not use 2 dictionary lookups: lower_case=>original_case, followed by original_case=>value (this is the solution which I am doing now instead)
如果您对应用案例感兴趣:这里是相应的分支
If you are interested in the application case: here is corresponding branch
推荐答案
在文件 dictobject.c
,你看到的是1795ff。相关代码:
In the file dictobject.c
, you see in line 1795ff. the relevant code:
static int
dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, char *methname)
{
PyObject *arg = NULL;
int result = 0;
if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg))
result = -1;
else if (arg != NULL) {
_Py_IDENTIFIER(keys);
if (_PyObject_HasAttrId(arg, &PyId_keys))
result = PyDict_Merge(self, arg, 1);
else
result = PyDict_MergeFromSeq2(self, arg, 1);
}
if (result == 0 && kwds != NULL) {
if (PyArg_ValidateKeywordArguments(kwds))
result = PyDict_Merge(self, kwds, 1);
else
result = -1;
}
return result;
}
这告诉我们,如果对象有一个属性键
,被调用的代码只是一个合并。在那里调用的代码(l。1915 ff。)区分了真实的dict和其他对象。在实际的情况下,用 PyDict_GetItem()
读取这些项目,这是该对象的最内在的接口,并且不会使用任何用户 -
This tells us that if the object has an attribute keys
, the code which is called is a mere merge. The code called there (l. 1915 ff.) makes a distinction between real dicts and other objects. In the case of real dicts, the items are read out with PyDict_GetItem()
, which is the "most inner interface" to the object and doesn't bother using any user-defined methods.
所以不要继承 dict
,你应该使用 UserDict
模块。
So instead of inheriting from dict
, you should use the UserDict
module.
这篇关于当从dict导出时,重载__iter__被绕过的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!