Dict-like类参数扩展

8 浏览
0 Comments

Dict-like类参数扩展

不使用继承dict的情况下,一个类需要满足什么条件才能被视为映射,从而可以传递给带有**的方法。\n

from abc import ABCMeta
class uobj:
    __metaclass__ = ABCMeta
uobj.register(dict)
def f(**k): return k
o = uobj()
f(**o)
# 输出:f() argument after ** must be a mapping, not uobj

\n至少要达到抛出映射缺失功能错误的程度,这样我才能开始实现。\n我查看了模拟容器类型的方法,但仅仅定义魔法方法没有效果,并且使用ABCMeta来重写并将其注册为dict验证了断言作为子类,但无法通过isinstance(o, dict)。理想情况下,我甚至不想使用ABCMeta

0
0 Comments

问题的出现原因是在使用非映射对象与`**`结合时,会出现`TypeError`错误。在CPython的源代码中搜索该错误,可以找到引发该错误的代码。代码位于`ceval.c`文件的3362行处,具体内容如下:

case TARGET(DICT_UPDATE): {
    PyObject *update = POP();
    PyObject *dict = PEEK(oparg);
    if (PyDict_Update(dict, update) < 0) {
        if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
            _PyErr_Format(tstate, PyExc_TypeError,
                            "'%.200s' object is not a mapping",
                            Py_TYPE(update)->tp_name);

通过查看`dictobject.c`文件中的代码,可以发现`PyDict_Update`实际上是`dict_merge`函数,当`dict_merge`返回负数时会抛出错误。进一步查看`dict_merge`的源代码,可以看到返回-1的情况:

/* We accept for the argument either a concrete dictionary object,
 * or an abstract "mapping" object.  For the former, we can do
 * things quite efficiently.  For the latter, we only require that
 * PyMapping_Keys() and PyObject_GetItem() be supported.
 */
if (a == NULL || !PyDict_Check(a) || b == NULL) {
    PyErr_BadInternalCall();
    return -1;

关键部分是这样描述的:

对于后者,我们只需要支持PyMapping_Keys()和PyObject_GetItem()。

这是否意味着只需要定义`getitem`和`keys`方法就可以呢?

一年多过去了,所以我不记得之前都发现了什么,但是是的,这正是该注释所暗示的。这个发现也在顶部的回答中得到了验证。我发布这个答案是为了展示如何找到这样的问题。

0
0 Comments

Dict-like Class Argument Expansion这个问题的出现原因是在创建Mapping时,有时候只满足函数传递的要求是不够的。为了满足Mapping的要求,需要继承自collections.abc.Mapping,并实现__getitem__、__len__和__iter__这三个方法。但是实现这些方法之外,还需要实现其他一些方法,比如__contains__、keys、items、values、get、__eq__和__ne__。解决这个问题的方法是使用collections.abc.Mapping作为基类,并实现所需的方法。这样,Mixin会自动为我们实现其他的方法,大大减少了工作量。在Python的文档中有详细的说明,可以参考文档进行实现。另外,这个问题的解决方法已经被移动到了collections.abc包中的文档中,可以在文档中查看相关内容。

0
0 Comments

问题的出现原因是在函数f的调用中,参数以Dict-like类的实例作为输入,并且在函数内部使用**kwds的形式进行参数扩展。在这种情况下,函数f会调用Dict-like类的keys()方法和__getitem__()方法来获取参数的键和值,然后将其作为关键字参数传递给函数。

其中,Dict-like类的keys()方法返回一个包含键的列表,而__getitem__()方法根据给定的键返回相应的值。在这个例子中,Dict-like类D的keys()方法返回['a', 'b'],而__getitem__()方法将给定的键转换为大写字母。

解决这个问题的方法是在Dict-like类中实现keys()方法和__getitem__()方法,使其能够正确返回键和值。这样,在函数f中使用**kwds进行参数扩展时,就能够正确地获取参数的键和值,并将其作为关键字参数传递给函数。

以上是关于(Dict-like Class Argument Expansion)问题的原因和解决方法的内容。

0