[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