Class that acts as mapping for **unpacking Class that acts as mapping for **unpacking python python

Class that acts as mapping for **unpacking


The __getitem__() and keys() methods will suffice:

>>> 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'}


If you're trying to create a Mapping — not just satisfy the requirements for passing to a function — then you really should inherit from collections.abc.Mapping. As described in the documentation, you need to implement just:

__getitem____len____iter__

The Mixin will implement everything else for you: __contains__, keys, items, values, get, __eq__, and __ne__.


The answer can be found by digging through the source.

When attempting to use a non-mapping object with **, the following error is given:

TypeError: 'Foo' object is not a mapping

If we search CPython's source for that error, we can find the code that causes that error to be raised:

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);

PyDict_Update is actually dict_merge, and the error is thrown when dict_merge returns a negative number. If we check the source for dict_merge, we can see what leads to -1 being returned:

/* 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;

The key part being:

For the latter, we only require that PyMapping_Keys() and PyObject_GetItem() be supported.