8000 bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__it… · python/cpython@cf22aa3 · GitHub
[go: up one dir, main page]

Skip to content

Commit cf22aa3

Browse files
bpo-42487: don't call __getitem__ of underlying maps in ChainMap.__iter__ (GH-23534) (GH-23569)
1 parent 03ae7e4 commit cf22aa3

File tree

3 files changed

+18
-1
lines changed

3 files changed

+18
-1
lines changed

Lib/collections/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ def __len__(self):
949949
def __iter__(self):
950950
d = {}
951951
for mapping in reversed(self.maps):
952-
d.update(mapping) # reuses stored hash values if possible
952+
d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible
953953
return iter(d)
954954

955955
def __contains__(self, key):

Lib/test/test_collections.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,22 @@ def test_order_preservation(self):
195195
('e', 55), ('f', 666), ('g', 777), ('h', 88888),
196196
('i', 9999), ('j', 0)])
197197

198+
def test_iter_not_calling_getitem_on_maps(self):
199+
class DictWithGetItem(UserDict):
200+
def __init__(self, *args, **kwds):
201+
self.called = False
202+
UserDict.__init__(self, *args, **kwds)
203+
def __getitem__(self, item):
204+
self.called = True
205+
UserDict.__getitem__(self, item)
206+
207+
d = DictWithGetItem(a=1)
208+
c = ChainMap(d)
209+
d.called = False
210+
211+
set(c) # iterate over chain map
212+
self.assertFalse(d.called, '__getitem__ was called')
213+
198214
def test_dict_coercion(self):
199215
d = ChainMap(dict(a=1, b=2), dict(b=20, c=30))
200216
self.assertEqual(dict(d), dict(a=1, b=2, c=30))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ChainMap.__iter__ no longer calls __getitem__ on underlying maps

0 commit comments

Comments
 (0)
0