Browse Source

bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__iter__ (GH-23534)

pull/23577/head
Andreas Poehlmann 6 years ago
committed by GitHub
parent
commit
0be9ce305f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Lib/collections/__init__.py
  2. 16
      Lib/test/test_collections.py
  3. 1
      Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst

2
Lib/collections/__init__.py

@ -1001,7 +1001,7 @@ class ChainMap(_collections_abc.MutableMapping):
def __iter__(self):
d = {}
for mapping in reversed(self.maps):
d.update(mapping) # reuses stored hash values if possible
d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible
return iter(d)
def __contains__(self, key):

16
Lib/test/test_collections.py

@ -196,6 +196,22 @@ class TestChainMap(unittest.TestCase):
('e', 55), ('f', 666), ('g', 777), ('h', 88888),
('i', 9999), ('j', 0)])
def test_iter_not_calling_getitem_on_maps(self):
class DictWithGetItem(UserDict):
def __init__(self, *args, **kwds):
self.called = False
UserDict.__init__(self, *args, **kwds)
def __getitem__(self, item):
self.called = True
UserDict.__getitem__(self, item)
d = DictWithGetItem(a=1)
c = ChainMap(d)
d.called = False
set(c) # iterate over chain map
self.assertFalse(d.called, '__getitem__ was called')
def test_dict_coercion(self):
d = ChainMap(dict(a=1, b=2), dict(b=20, c=30))
self.assertEqual(dict(d), dict(a=1, b=2, c=30))

1
Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst

@ -0,0 +1 @@
ChainMap.__iter__ no longer calls __getitem__ on underlying maps
Loading…
Cancel
Save