[Python-Dev] Mundane dict __setitem__...

David Abrahams dave@boost-consulting.com
Tue, 03 Jun 2003 12:15:06 -0400


"Tim Peters" <tim@zope.com> writes:

> [David Abrahams]
>>> I am about to write some code which relies on the following:
>>>
>>>     x = (1,2,3)
>>>     y = (1,2,3)
>>>     d = {}
>>>     d[x] = 1
>>>     d[y] = 1
>>>     assert d.keys()[0] is y
>>>
>>> In other words, when you do d[k] = v it replaces both v *and* k in
>>> the dict.  I couldn't find it documented anywhere but the source.  I
>>> submitted a doc patch which enshrines that behavior, but since Guido
>>> doesn't always know what's in the doc I wanted to make sure it was
>>> considered reasonable.
>>>
>>> Anyone want to tell me it's a bad idea?  It seems like the more
>>> useful of the two possible behaviors to me.
>
> [Samuele Pedroni]
>> that's not the case with Jython, i.e. the assert will fail in Jython.
>
> It probably fails in CPython too:
>
>>>> x = (1, 2, 3)
>>>> y = (1, 2, 3)
>>>> d = {x: 1}
>>>> d[y] = 1
>>>> map(id, d.keys())  # shows that x is still a key
> [7872560]
>>>> id(x), id(y)
> (7872560, 8348336)
>>>>
>
> Dave, what made you think x gets replaced?

The source, Luke.  But sadly I was just mis-reading the wrong branch
of the if clause.  It's hard to understand why that Py_DECREF is
needed, but it was just the distraction my hopeful brain needed to
tell me it would work ;-(

    static void
    insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value)
    {
        PyObject *old_value;
        register dictentry *ep;
        typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long);

        assert(mp->ma_lookup != NULL);
        ep = mp->ma_lookup(mp, key, hash);
        if (ep->me_value != NULL) {
            old_value = ep->me_value;
            ep->me_value = value;
            Py_DECREF(old_value); /* which **CAN** re-enter */
            Py_DECREF(key);
        }
        else {
            if (ep->me_key == NULL)
                mp->ma_fill++;
            else
                Py_DECREF(ep->me_key);
                ^^^^^^^^^^^^^^^^^^^^^
            ep->me_key = key;


-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com