[Tutor] question about __copy__ and __deepcopy__

Oscar Benjamin oscar.j.benjamin at gmail.com
Fri Apr 15 05:31:53 EDT 2016


On 15 April 2016 at 09:55, Albert-Jan Roskam <sjeik_appie at hotmail.com> wrote:
>
> Heh, it's my fancy __str__ method that confused me. This is what I get when I run my code without __copy__ and __deepcopy__
> runfile('/home/albertjan/Downloads/attrdict_tutor.py', wdir='/home/albertjan/Downloads')
> {'x': 1, 'y': 2, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]} {'x': 1, 'y': 2, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
> {'x': 1, 'y': 2, 'z': [42, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]} {}   # print statements --> call __str__
>
> dc.__str__()
> Out[19]: '{}'
>
> dc.__repr__()
> Out[20]: "{'y': 2, 'x': 1, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}"
>
> Wicked. I do not understand the output of dc.__str__(). Somehow self.__dict__ is empty. If I store a deepcopy of the instance __dict__ in a class attribute "Record.dict_copy", __str__ does not return just the two curly braces. It's wasteful to create a copy, though.

This kind of confusion comes from setting self.__dict__ = self. That's
not really a normal thing to do so I wouldn't expect it to necessarily
be supported by other things like copy.copy:

In [1]: class Record(dict):
   ...:     def __init__(self, *args, **kwargs):
   ...:         super(Record, self).__init__(*args, **kwargs)
   ...:         self.__dict__ = self
   ...:

In [2]: r = Record(x=1, y=2)

In [3]: r
Out[3]: {'x': 1, 'y': 2}

In [4]: r.__dict__ is r    # <--- Compare with r2 below
Out[4]: True

In [5]: import copy

In [6]: r2 = copy.copy(r)

In [7]: r2
Out[7]: {'x': 1, 'y': 2}

In [8]: r2.__dict__
Out[8]: {'x': 1, 'y': 2}

In [9]: r2 is r2.__dict__  # <-- self.__dict__ is not self
Out[9]: False

In [13]: type(r2.__dict__)
Out[13]: dict

In [14]: type(r.__dict__)
Out[14]: __main__.Record

In [15]: r2.__dict__ == r.__dict__  # <-- Equal but distinct
Out[15]: True

--
Oscar


More information about the Tutor mailing list