Python 类,该类充当**解包的映射

Python 类,该类充当**解包的映射,python,class,mapping,argument-unpacking,Python,Class,Mapping,Argument Unpacking,如果不将dict子类化,类需要被视为映射,以便可以通过**将其传递给方法 from abc import ABCMeta class uobj: __metaclass__ = ABCMeta uobj.register(dict) def f(**k): return k o = uobj() f(**o) # outputs: f() argument after ** must be a mapping, not uobj 至少在某种程度上,它会抛出缺少映射功能的错误,

如果不将dict子类化,类需要被视为映射,以便可以通过
**
将其传递给方法

from abc import ABCMeta

class uobj:
    __metaclass__ = ABCMeta

uobj.register(dict)

def f(**k): return k

o = uobj()
f(**o)

# outputs: f() argument after ** must be a mapping, not uobj
至少在某种程度上,它会抛出缺少映射功能的错误,这样我就可以开始实现了

我回顾了模拟容器类型,但简单地定义魔术方法没有效果,使用
ABCMeta
重写并注册为dict将断言验证为子类,但失败
isinstance(o,dict)
。理想情况下,我甚至不想使用
ABCMeta

方法
\uu getitem\uuuuuuuuuuu()
keys()
就足够了:

>>> class D:
        def keys(self):
            return ['a', 'b']
        def __getitem__(self, key):
            return key.upper()


>>> def f(**kwds):
        print kwds


>>> f(**D())
{'a': 'A', 'b': 'B'}

如果您试图创建一个映射,而不仅仅是满足传递给函数的要求,那么您真的应该从
collections.abc.Mapping
继承。如中所述,您只需实现:

__getitem__
__len__
__iter__

Mixin将为您实现所有其他功能:
\uuuuu包含
获取
\uuuuuuuuuuu情商
,以及
通过挖掘源代码可以找到答案

尝试将非映射对象与
**
一起使用时,会出现以下错误:

TypeError: 'Foo' object is not a mapping
如果我们搜索CPython的错误源,我们可以找到:

关键部分是:

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


超出范围,但具有相关性和信息量,谢谢有用。这已经转移到了collections.abc软件包中:@StuartBuckingham我感谢你的谦虚,但下次请随意编辑我的答案:)啊,我不知道这是可能的。谢谢@Neig
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);
/* 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;