Visitar URL original
gh-98766: Lazier ChainMap methods by zrothberg · Pull Request #98767 · python/cpython · GitHub
Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Lazy slicing and iter
  • Loading branch information
zrothberg committed Oct 27, 2022
commit 71b6de5e626078a1c7c9eef531dac826fbe439c3
10 changes: 5 additions & 5 deletions Lib/collections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from itertools import chain as _chain
from itertools import repeat as _repeat
from itertools import starmap as _starmap
from itertools import islice as _isclice
Comment thread
zrothberg marked this conversation as resolved.
Outdated
from keyword import iskeyword as _iskeyword
from operator import eq as _eq
from operator import itemgetter as _itemgetter
Expand Down Expand Up @@ -1010,9 +1011,8 @@ def __len__(self):
return len(set().union(*self.maps)) # reuses stored hash values if possible

def __iter__(self):
d = {}
for mapping in reversed(self.maps):
d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible
lazy_views = (keyview.keys() for keyview in reversed(self.maps))
d = dict.fromkeys(_chain.from_iterable(lazy_views))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't do what you think it does. The chain extracts the keys from the views and then passes those through to dict.fromkeys(). That defeats the goal of retaining the precomputed hash values stored in the underlying mapping.

The dict.fromkeys() class method can use the precomputed hash values ONLY if the input is an exact dict or exact set. An iterable of keys will not suffice.

Also, there isn't any "laziness" at all in these two lines. You make a generator expression and then consume it immediately. It is not much different from converting sum([10, 20, 30]) to sum(iter([10, 20, 30]))` and calling it "lazy".

return iter(d)

def __contains__(self, key):
Expand All @@ -1032,7 +1032,7 @@ def fromkeys(cls, iterable, *args):

def copy(self):
'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
return self.__class__(self.maps[0].copy(), *self.maps[1:])
return self.__class__(self.maps[0].copy(), *_isclice(self.maps, 1, None))

__copy__ = copy

Expand All @@ -1050,7 +1050,7 @@ def new_child(self, m=None, **kwargs): # like Django's Context.push()
@property
def parents(self): # like Django's Context.pop()
'New ChainMap from maps[1:].'
return self.__class__(*self.maps[1:])
return self.__class__(*_isclice(self.maps, 1, None))

def __setitem__(self, key, value):
self.maps[0][key] = value
Expand Down