diff options
author | Andreas Poehlmann <andreas@poehlmann.io> | 2020-11-30 16:34:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-30 16:34:15 (GMT) |
commit | 0be9ce305ff2b9e13ddcf15af8cfe28786afb36a (patch) | |
tree | 6adbae3b5c36f2c9588e68112f02371e4d995da6 | |
parent | 9f004634a2bf50c782e223e2eb386ffa769b901c (diff) | |
download | cpython-0be9ce305ff2b9e13ddcf15af8cfe28786afb36a.zip cpython-0be9ce305ff2b9e13ddcf15af8cfe28786afb36a.tar.gz cpython-0be9ce305ff2b9e13ddcf15af8cfe28786afb36a.tar.bz2 |
bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__iter__ (GH-23534)
-rw-r--r-- | Lib/collections/__init__.py | 2 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 16 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst | 1 |
3 files changed, 18 insertions, 1 deletions
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index 5d75501..9c25a2d 100644 --- a/Lib/collections/__init__.py +++ b/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): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 150c2a1..a1ca958 100644 --- a/Lib/test/test_collections.py +++ b/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)) diff --git a/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst b/Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst new file mode 100644 index 0000000..8c67d74 --- /dev/null +++ b/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 |