[Python-ideas] Syntax for key-value iteration over mappings

Steven D'Aprano steve at pearwood.info
Mon Jul 27 21:17:10 CEST 2015

On Tue, Jul 28, 2015 at 02:25:00AM +1000, Chris Angelico wrote:

> What my suggestion was positing was not so much DWIM as "iterate over
> the keys and values of anything". A mapping type has a concept of keys
> and values; an indexable sequence (list, tuple, etc) uses sequential
> numbers as indices and its members as values.

Keys and indices are not the same thing, and Python is not Lua.

While there are certain similarities between the indices of a sequence 
and the keys of a mapping, they really don't play the same role in any 
meaningful sense. Consider:

x in mapping  # looks for a key x
x in sequence  # looks for a value x, not an index ("key") x

Consider this too:

mapping = {i:i**2 for i in range(1000)}
sequence = [i**2 for i in range(1000)]
for obj in (mapping, sequence):
   while 0 in obj.keys():
       del obj[0]
   assert 0 not in obj.keys()

The first problem is that lists don't have a keys() method. But that's 
okay, pretend that we've added one. Now your problems have only begun:

len(mapping)  # returns 1000-1
len(sequence)  # returns 0

Well that sucks.

Deleting (or inserting) a item into a sequence potentially changes the 
"keys" of all the other items. What sort of a mapping does that?

Despite the apparent analogy of key <=> index, it's remarkable hard to 
think of any practical use for such a thing. I cannot think of any time 
I have wanted to, or might want to in the future, ducktype lists as 
dicts, with the indices treated as keys.

The closest I can come up to is to support Lua-like arrays implemented 
as tables (mappings). When you create an array in Lua, it's not actually 
an array like in Python or a linked-list like in Lisp, but a (hash) 
table where the keys are automatically set to 1, 2, ... n by the 
interpreter. But that's just sugar for convenience. Lua arrays are still 
tables, they merely emulate arrays. And besides, that's the opposite: 
treating keys as indices, not indices as keys.

Apart from practical problems such as the above, there's also a 
conceptual problem. Keys of a mapping are *intrinsic* properties of the 
mapping. But indices of a sequence are *extrinsic* properties. They 
aren't actually part of the sequence. Given the list [2,4,6] the "key" 
(actually index) 0 is not part of the list in any way.

Some languages, like C and Python, treat those indices as starting from 
0. Others treat them as starting from 1. Fortran and Pascal, if I 
remember correctly, let you index arrays over any contiguous range of 
integers, including negatives:

foo = array[-20...20] of integer;

or something like that.

Conveniently the way we access keys and indices reflects this. Keys, 
being intrinsic to the mapping, is a method:


while indices, being extrinsic, is a function which can be applied to 
any iterable, with any starting value:

    enumerate(sequence, 1)
    enumerate(mapping, -5)

[... snip proposal to treat sets {element} as {element:True} ...]

> This would create a new iteration invariant. We currently have:

Why do we need this invariant? What does it gain us to be able to say


and get True back, regardless of the value of element? Why not just say:


We can invent any invariants we like, but if they're not useful, why add 
cruft to the language to support something that we aren't going to use?


More information about the Python-ideas mailing list