[Python-Dev] Possible wrong behavior of the dict?

Brett Cannon brett at python.org
Tue Mar 17 20:38:59 CET 2015


On Tue, Mar 17, 2015 at 3:29 PM Zaur Shibzukhov <szport at gmail.com> wrote:

> Yes... But I expected that dict constructor will use `__getitem__`  or
> `items` method of MyDict instance  in order to retrieve items of the MyDict
> instance during construction of the dict instance... Instead it interpreted
> MyDict instance as the dict instance during construction of new dict.This
> exactly caused my confusion.
>

It's because you subclassed dict. Copying is optimized to skip over using
the methods you listed when the object is a dict and so we know the
structure of the object at the C level. You can look at
https://hg.python.org/cpython/file/22a0c925a7c2/Objects/dictobject.c#l1997
to see the actual code.

-Brett


>
> ---
> *Zaur Shibzukhov*
>
>
> 2015-03-17 22:12 GMT+03:00 Brett Cannon <brett at python.org>:
>
>>
>>
>> On Tue, Mar 17, 2015 at 3:05 PM Zaur Shibzukhov <szport at gmail.com> wrote:
>>
>>> Hello!
>>>
>>> In order to explain, let define subclass of dict:
>>>
>>> class Pair:
>>>     def __init__(self, key, val):
>>>         self.key = key
>>>         self.val = val
>>>
>>> class MyDict(dict):
>>>     #
>>>     def __init__(self, *args, **kwds):
>>>         if len(args) > 1:
>>>             raise TypeError('Expected at most 1 arguments, but got %d' %
>>> len(args))
>>>
>>>         for key, val in args[0]:
>>>             self[key] = val
>>>
>>>         for key, val in kwds.items():
>>>             self[key] = val
>>>
>>>     def __getitem__(self, key):
>>>         pair = dict.__getitem__(key)
>>>         return pair.value
>>>
>>>     def __setitem__(self, key, val):
>>>         if key in self:
>>>             pair = dict.__getitem__(key)
>>>             pair.value = value
>>>         else:
>>>             pair = Pair(key, val)
>>>             dict.__setitem__(self, key, pair)
>>>
>>>     def values(self):
>>>         for key in self:
>>>             p = dict.__getitem__(self, key)
>>>             yield p.value
>>>
>>>     def items(self):
>>>         for key, p in dict.__iter__(self):
>>>             yield p.key, p.value
>>>
>>>
>>> The simple test give me strange result:
>>>
>>> >>> d = MyDict([('a', 1), ('b', 2), ('c', 3)])
>>> >>> dict(d)
>>> {'a': <__main__.Pair at 0x104ca9e48>,
>>>  'b': <__main__.Pair at 0x104ca9e80>,
>>>  'c': <__main__.Pair at 0x104ca9eb8>}
>>>
>>> instead of {'a':1, 'b':2, 'c':3}.
>>>
>>>
>>> Is this right behavior of the dict?
>>>
>>
>> Yes because in your __setitem__ call you are storing the value as the
>> Pair. So when dict prints its repr it prints the key and value, and in this
>> case the value is a Pair.
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150317/a0e65e0f/attachment.html>


More information about the Python-Dev mailing list