Why is dictionary.keys() a list and not a set?

Christoph Zwerschke cito at online.de
Wed Nov 23 18:15:27 EST 2005


Ok, the answer is easy: For historical reasons - built-in sets exist 
only since Python 2.4.

Anyway, I was thinking about whether it would be possible and desirable 
to change the old behavior in future Python versions and let dict.keys() 
and dict.values() both return sets instead of lists.

If d is a dict, code like:

for x in d.keys():
     ...

or even

for x in sorted(d.keys()):
     ...

would still work and do the same.

However, the older idiom

k = d.keys()
k.sort()
for x in k:
     ...

would break (since you cannot sort a map directly).

So it seems not possible to change the behavior since it would break old 
code. Maybe keys() and values() could be made deprecated functions, 
superseded by keyset() and valueset(), but probably this would not be 
worth the effort.

Another related question: Actually, dicts can be considered as 
subclasses of sets and thus could inherit a lot of set methods and 
operators. Only intersection and union must be treated with care, 
because dictionaries must be mappings (i.e. map to exactly one value).

In fact, some inheritance from sets has already been implemented:

For instance, by allowing the set operator "in" for dictionaries, 
instead of "has_key".

The len(), clear(), copy() and update() functions can also be 
interpreted as inherited from set. The dictionary method popitem() is 
actually the inherited set method pop(). (d.pop() without arguments 
could actually do the same as d.popitem(); I guess the suffix "item" was 
chosen to remind you that it returns a key/value pair, not only a value.)

But could other set methods also be useful?

A dictionary could inherit the remove() and discard() method from sets. 
d.remove(x) would do the same as del d[x], but d.discard(x) would not 
raise a KeyError if x not in d.

Or, for instance, if

a = { 1:11, 2:12 }; b = { 2:22, 3:13 }, c = { 2:32 }

then

c.issubset(b)  ==  c <= b  == True
b.issuperset(c)  ==  b >= c  == True
a.difference(b)  ==  a - b  == { 1:11 }
a.s.symmetric_difference(b) ==  a ^ b  ==  { 1:11, 3:13 }
a.update(b)  ==  a |= b  ==  a = { 1:11, 2:22, 3:13 }
a.intersection_update(b)  ==  a &= b  ==   a = { 2:22 }
a.difference_update(b) ==  a -= b  ==  a = { 1:11 }
a.symmetric_difference_update(b) ==  a ^= b  == a = { 1:11, 3:13 }

Of these, a |= b may be particularly interesting as short notation for 
a.update(b).

-- Christoph



More information about the Python-list mailing list