[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:
mapping.keys()
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
myset[element]
and get True back, regardless of the value of element? Why not just say:
True
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?
--
Steve
More information about the Python-ideas
mailing list