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

2015-03-17 Thread Zaur Shibzukhov
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?

---
Zaur Shibzukhov
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2015-03-17 Thread Zaur Shibzukhov
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.

---
*Zaur Shibzukhov*


2015-03-17 22:12 GMT+03:00 Brett Cannon :

>
>
> On Tue, Mar 17, 2015 at 3:05 PM Zaur Shibzukhov  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.
>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2015-03-17 Thread Zaur Shibzukhov
So in such cases it should not subclassed `dict`, but
`collections.MutableMapping`, for example?

---
*Zaur Shibzukhov*


2015-03-17 22:38 GMT+03:00 Brett Cannon :

>
>
> On Tue, Mar 17, 2015 at 3:29 PM Zaur Shibzukhov  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 :
>>
>>>
>>>
>>> On Tue, Mar 17, 2015 at 3:05 PM Zaur Shibzukhov 
>>> 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.
>>>
>>
>>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


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

2015-03-17 Thread Zaur Shibzukhov
Thanks.

---
*Zaur Shibzukhov*


2015-03-17 22:48 GMT+03:00 Brett Cannon :

>
>
> On Tue, Mar 17, 2015 at 3:46 PM Zaur Shibzukhov  wrote:
>
>> So in such cases it should not subclassed `dict`, but
>> `collections.MutableMapping`, for example?
>>
>
> Yes (see the comment at
> https://hg.python.org/cpython/file/22a0c925a7c2/Objects/dictobject.c#l2003
> ).
>
> -Brett
>
>
>>
>> ---
>> *Zaur Shibzukhov*
>>
>>
>> 2015-03-17 22:38 GMT+03:00 Brett Cannon :
>>
>>>
>>>
>>> On Tue, Mar 17, 2015 at 3:29 PM Zaur Shibzukhov 
>>> 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 :
>>>>
>>>>>
>>>>>
>>>>> On Tue, Mar 17, 2015 at 3:05 PM Zaur Shibzukhov 
>>>>> 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.
>>>>>
>>>>
>>>>
>>
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com