[Python-ideas] Syntax for key-value iteration over mappings
Steven D'Aprano
steve at pearwood.info
Mon Jul 27 04:12:09 CEST 2015
On Sun, Jul 26, 2015 at 06:09:17PM +0200, Petr Viktorin wrote:
> Hello,
> Currently, the way to iterate over keys and values of a mapping
> is to call items() and iterate over the resulting view::
>
> for key, value in a_dict.items():
> print(key, value)
>
> I believe that looping over all the data in a dict is a very imporant
> operation, and I find myself writing this quite often. Every time I do,
> it seems it's boilerplate;
What part looks like boilerplate? The "for"? The "key,value"? The "in"?
The "a_dict"? If none of them are boilerplate, why would ".items()" be
boilerplate?
> it looks a like a workaround rather than a
> preferred way of doing things.
A work-around for what? It can't be "work-around for lack of a way to
get the (key,value) pairs from a dict", because the items() method *is*
the preferred way to get the (key,value) pairs from a dict, and has been
since Python 1.5 or even older.
I don't think that describing an explicit call to items() method as
"boilerplate" or "a work-around" can be justified. If it is either, then
the terms are so meaningless that they could be applied to anything at
all.
> In dict comprehensions and literals, key-value pairs are separated by
> colons. How about allowing that in for loops as well?
>
> for key: value in a_dict:
> print(key, value)
A very strong -1 to this.
It's ugly and unattractive. "for x:" looks like the end of a statement,
not the beginning of one.
Yes, as you point out, we can already write a similarly ugly statement
"while lambda: None:" but nobody does, and just because existing syntax
accidently allows one ugly construct doesn't give an excuse to
deliberately add an ugly construct.
It's one more special case syntax for beginners to learn. And it really
is a special case: there's nothing about "for k:v in iterable" that
tells you that iterable must have an items() method. You have to
memorise that fact.
Being a special case, you can only use this for iterables that have an
items() method. You can't do:
for k:v in [(1, 'a'), (2, 'b')]: ...
because the list doesn't have an items() method.
In dict literals and dict comprehensions, the k:v syntax is only used to
construct the dict, not to extract items from it. We have a standard way
of doing sequence bindings:
a, b = ... # right-hand side must be a sequence of two items
and the standard way of extracting (key, value) pairs from a mapping is
the items() method. If you know that a mapping has only one item, we can
even write:
[[key, value]] = mapping.items()
and sequence unpacking will do the work for us. Do you expect this to
work too?
[key:value] = mapping
This proposed syntactic sugar doesn't add any new functionality or make
anything simpler. It just saves you eight keystrokes in one special
case.
--
Steve
More information about the Python-ideas
mailing list