On Sun, 8 Jan 2017 08:48 am, Ethan Furman wrote: > In Python 2 we have: > > dict().keys() \ > dict().items() --> separate list() of the results > dict().values() / > > and > > dict().iter_keys() \ > dict().iter_items() --> integrated iter() of the results > dict().iter_values() /
You missed another group of methods: viewkeys() viewitems() viewvalues() which are integrated, iterable, set-like views of the keys/items/values. > By "separate list" I mean a snapshot of the dict at the time, and by > "integrated iter()" I mean changes to the dict during iteration are > seen by the iter. > > In Python 3 the iter_* methods replaced the list() type methods, Its actually the view* methods. > which > makes sense from the point-of-view of moving to a more iterator based > language; however, as a result of that change the typical "iterate over > a dict" operation now has a built-in gotcha: modifying the dict during > the iteration can now cause exceptions. Even in Python 2, modifying the dict during iteration can cause exceptions: for key in adict: # iterate over the dict directly ... As usual, the standard rule applies: don't add or remove elements of a collection while you are iterating over it. This doesn't work either: for i, x in enumerate(alist): if condition(x): del alist(i) and has a similar solution: for i, x in enumerate(list(alist)): ... except that's more commonly written using slicing: for i, x in enumerate(alist[:]): ... For both dicts and lists, it is safe to modify existing elements: adict[key] = new_value # provided key already exists alist[index] = new_value are both safe, but insertions and deletions are not. > The solution, of course, is simple: surround the iterator call with > list(): There's nothing magical about list. You could use tuple, or (sometimes) set or frozenset. But list is good. > list(dict.keys()) > list(dict.items()) > list(dict.values()) > > for k, v in list(flag._value2member_map_.items()): > ... > > The solution, however, feels a lot more boilerplate-ish. Either the > programmer takes a lot more care to remember the current state of the dict > (since it's no longer a snapshot), or "list()" is sprinkled around every > iterator access. Not *every* view access. Only the ones where you insert/delete elements. > In other words, what used to be a completely safe operation now is not. > > Thoughts? The old Python 2 keys/values/items methods used to make a copy of the elements, whether you needed a copy or not. Now making a copy is your responsibility. That feels more Pythonic to me. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list