Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does python's dict constructor handle Mappings?

What does dict(mapping) actually do?

Background:

Python's docs suggest there are three possible paths when constructing a dict, one of which is with a Mapping.

A pandas series is similar to a dict in some ways, and coercing to a dict works as expected:

In [27]: series=pd.Series({'a':2,'b':3})

In [28]: dict(series)
Out[28]: {'a': 2, 'b': 3}

But when inside a ChainMap, this goes awry:

In [25]: dict(ChainMap(series))

... which should be equivalent to the first expression, I think, but instead...

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/index.py in get_value(self, series, key)
   1789         try:
-> 1790             return self._engine.get_value(s, k)
   1791         except KeyError as e1:

pandas/index.pyx in pandas.index.IndexEngine.get_value (pandas/index.c:3204)()

pandas/index.pyx in pandas.index.IndexEngine.get_value (pandas/index.c:2903)()

pandas/index.pyx in pandas.index.IndexEngine.get_loc (pandas/index.c:3843)()

pandas/hashtable.pyx in pandas.hashtable.PyObjectHashTable.get_item (pandas/hashtable.c:12265)()

pandas/hashtable.pyx in pandas.hashtable.PyObjectHashTable.get_item (pandas/hashtable.c:12216)()

KeyError: 2

During handling of the above exception, another exception occurred:

IndexError                                Traceback (most recent call last)
<ipython-input-25-ffe959c53a67> in <module>()
----> 1 dict(ChainMap(series))

/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/collections/__init__.py in __getitem__(self, key)
    865         for mapping in self.maps:
    866             try:
--> 867                 return mapping[key]             # can't use 'key in mapping' with defaultdict
    868             except KeyError:
    869                 pass

/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/series.py in __getitem__(self, key)
    555     def __getitem__(self, key):
    556         try:
--> 557             result = self.index.get_value(self, key)
    558 
    559             if not np.isscalar(result):

/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/pandas/core/index.py in get_value(self, series, key)
   1794 
   1795             try:
-> 1796                 return tslib.get_value_box(s, key)
   1797             except IndexError:
   1798                 raise

pandas/tslib.pyx in pandas.tslib.get_value_box (pandas/tslib.c:16375)()

pandas/tslib.pyx in pandas.tslib.get_value_box (pandas/tslib.c:16126)()

IndexError: index out of bounds

FWIW this does work:

In [29]: dict(ChainMap(dict(series)))
Out[29]: {'a': 2, 'b': 3}

...so ChainMap seems to be calling parts of the interface of Series that dict doesn't call. I can't work out what, because I can't seem to find Python-code that replicates what dict(mapping) does.

like image 657
Maximilian Avatar asked Jul 14 '26 05:07

Maximilian


1 Answers

It looks like series aren't really true mappings... Note that iterating over the series yields the values, not the keys:

>>> list(series)
[2, 3]

collections.ChainMap relies on the fact that iterating over a mapping should yield the keys.

Apparently, the dict constructor doesn't rely on this fact (IIRC, it uses the .keys method -- for which pandas returns a suitable object).

like image 111
mgilson Avatar answered Jul 17 '26 20:07

mgilson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!