What is a mapping object, according to dict type?

2019-01-20 08:04发布

问题:

The documentation lists 3 ways for creating a dict instance:

class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)

What exactly is a mapping here? What's the minimal interface required for dict(mapping) to work?

回答1:

As usual, feel free to peruse the code :)

So, let's go into Include/dictobject.h:

132 /* PyDict_Merge updates/merges from a mapping object (an object that
133    supports PyMapping_Keys() and PyObject_GetItem()).  If override is true,
134    the last occurrence of a key wins, else the first.  The Python
135    dict.update(other) is equivalent to PyDict_Merge(dict, other, 1).
136 */

So we're looking for things that have PyMapping_Keys and PyObject_GetItem. Because we're lazy, we just use the search box in the python docs and find the mappings protocol. So if your CPython PyObject follows that protocol, you're good to go.



回答2:

From the source code for CPython, this comment:

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

So, "the minimal interface required for dict(mapping) to work" appears to be .keys() and .__getitem__().

Example program:

class M:
    def keys(self):
        return [1,2,3]
    def __getitem__(self, x):
        return x*2

m = M()

d = dict(m)

assert d == {1:2, 2:4, 3:6}


回答3:

The glossary defines it as:

A container object that supports arbitrary key lookups and implements the methods specified in the Mapping or MutableMapping abstract base classes. Examples include dict, collections.defaultdict, collections.OrderedDict and collections.Counter.

So it looks like the minimal list of methods to meet the definition is __getitem__, __iter__, __len__, __contains__, keys, items, values, get, __eq__, and __ne__. Although I bet the dict constructor does not actually need all of those.



回答4:

It seems that implementing only keys and __getitem__ is sufficient.

>>> class mydict:
...     def keys(self):
...         return 'xyz'
...     def __getitem__(self, item):
...         return 'potato'
...     
>>> dict(mydict())
{'x': 'potato', 'y': 'potato', 'z': 'potato'}


回答5:

It's the best answer for your question:

https://docs.python.org/2/library/stdtypes.html#typesmapping

It's the simplest example of mapping: {}

If you want to create a custom mapping type, you may inherit it from base dict and overwrite __getitem__ magic method(it depends on your needs)