]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__iter__ (GH-23534)
authorAndreas Poehlmann <andreas@poehlmann.io>
Mon, 30 Nov 2020 16:34:15 +0000 (17:34 +0100)
committerGitHub <noreply@github.com>
Mon, 30 Nov 2020 16:34:15 +0000 (08:34 -0800)
Lib/collections/__init__.py
Lib/test/test_collections.py
Misc/NEWS.d/next/Library/2020-11-28-04-31-20.bpo-42487.iqtC4L.rst [new file with mode: 0644]

index 5d75501645fc4a7ec8e7c0cdadea7a8a0f9bd12f..9c25a2d2784b8f1454a374eb21e4e91a24969748 100644 (file)
@@ -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):
index 150c2a1c0e3498e45c5d2080592a958aad48419d..a1ca958257adf6af64869a551fd658623b701be8 100644 (file)
@@ -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 (file)
index 0000000..8c67d74
--- /dev/null
@@ -0,0 +1 @@
+ChainMap.__iter__ no longer calls __getitem__ on underlying maps