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?
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?
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.
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}
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
andcollections.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.
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'}
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)