Python 3: dict & dict.keys()

Chris Angelico rosuav at gmail.com
Thu Jul 25 10:15:22 CEST 2013


On Thu, Jul 25, 2013 at 5:27 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> On Thu, 25 Jul 2013 16:02:42 +1000, Chris Angelico wrote:
>
>> On Thu, Jul 25, 2013 at 3:48 PM, Steven D'Aprano
>> <steve+comp.lang.python at pearwood.info> wrote:
>>> Dicts aren't sets, and don't support set methods:
>>>
>>> py> d1 - d2
>>> Traceback (most recent call last):
>>>   File "<stdin>", line 1, in <module>
>>> TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
>>
>> I wouldn't take this as particularly significant, though. A future
>> version of Python could add that support (and it might well be very
>> useful), without breaking any of the effects of views.
>
> I don't think dicts can ever support set methods, since *they aren't
> sets*. Every element consists of both a key and a value, so you have to
> consider both. Set methods are defined in terms of singleton elements,
> not binary elements, so before you even begin, you have to decide what
> does it mean when two elements differ in only one of the two parts?
>
> Given dicts {1: 'a'}, {1: 'b'}, what is the union of them? I can see five
> possibilities:
>
> {1: 'a'}
> {1: 'b'}
> {1: ['a', 'b']}
> {1: set(['a', 'b'])}
> Error
>
> Each of the five results may be what you want in some circumstances. It
> would be a stupid thing for dict.union to pick one behaviour and make it
> the One True Way to perform union on two dicts.

That's true, but we already have that issue with sets. What's the
union of {0} and {0.0}? Python's answer: It depends on the order of
the operands.

>>> i={0}
>>> f={0.0}
>>> i | f
{0}
>>> f | i
{0.0}

I would say that Python can freely pick from the first two options you
offered (either keep-first or keep-last), most likely the first one,
and it'd make good sense. Your third option would be good for a few
specific circumstances, but then you probably would also want the
combination of {1:'a'} and {1:'a'} to be {1:['a','a']} for
consistency. This would make a good utility function, but isn't what
I'd normally see set union doing. Similarly with the fourth option,
though there it's a little more arguable. Raising an error would work,
but is IMO unnecessary.

(Pike has dictionary operations, but has made different choices. For
instance, 0 and 0.0 are considered distinct, so a set can contain
both. Mappings (dicts) merge by keeping the last, not the first. But
the specifics don't much matter.)

A Python set already has to distinguish between object value and
object identity; a dict simply adds a bit more distinction between
otherwise-considered-identical keys, namely their values.

>>> a="This is a test."
>>> b="This is a test."
>>> a is b
False
>>> id(a)
16241512
>>> id(b)
16241392
>>> id(({a}|{b}).pop())
16241512

Assuming a and b have different ids, which is true in the above
example of Py3.3 on Windows, the set union *must* be different from
one of them. Suppose you do a dictionary of id(key) -> value, and a
set of the keys themselves. You could then do set operations on the
keys, and then go and retrieve the values.

Sure, maybe the way of doing things won't be exactly what everyone
expects... but it works, and it makes plausible sense. And as a
theoretical "might be implemented in Python 3.5", it still has no
impact on views, beyond that there are some operations which must be
done with views in <=3.3 that could be done on the dicts themselves in
future.

ChrisA



More information about the Python-list mailing list