[Tutor] question about __copy__ and __deepcopy__
Albert-Jan Roskam
sjeik_appie at hotmail.com
Fri Apr 15 04:55:20 EDT 2016
> Date: Fri, 15 Apr 2016 16:30:16 +1000
> From: steve at pearwood.info
> To: tutor at python.org
> Subject: Re: [Tutor] question about __copy__ and __deepcopy__
>
> On Thu, Apr 14, 2016 at 07:38:31PM +0000, Albert-Jan Roskam wrote:
> > Hi,
> >
> > Lately I have been using the "mutable namedtuple" shown below a lot.
> > I found it somewhere on StackOverflow or ActiveState or something. In
> > its original form, it only had an __init__ method. I noticed that
> > copying Record objects sometimes failed.
>
> Failed how?
>
> Given how simple the class looks, I wonder whether that's a bug in copy.
> Apart from a fancy __str__ method, there's practically nothing to it!
>
> So I took your Record class, stripped out the __copy__ and __deepcopy__
> methods, created a slightly complex instance, and tried copying it:
>
> d = Record(spam=23, ham=42, eggs=[], cheese={})
> d.cheese[1] = None
> d.cheese[2] = ['a', 'b', 'c']
> d.eggs.append(100)
> d.eggs.append(200)
> d.eggs.append(d)
> d.eggs.append(d.cheese)
>
> from copy import copy, deepcopy
>
> copy(d)
> deepcopy(d)
>
>
> and both appeat to work correctly. So perhaps you ought to look more
> carefully at the copying failure?
Hi Steven,
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.
from copy import copy, deepcopy
class Record(dict):
def __init__(self, *args, **kwargs):
super(Record, self).__init__(*args, **kwargs)
self.__dict__ = self
def __str__(self):
#items = ["%r: %r" % (k, v) for k, v in sorted(self.__dict__.items())]
Record.dict_copy = deepcopy(self) # store it as a class attribute.
items = ["%r: %r" % (k, v) for k, v in sorted(Record.dict_copy.items())]
return "{" + ", ".join(items) + "}"
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]} {'x': 1, 'y': 2, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
dc.__str__()
Out[28]: "{'x': 1, 'y': 2, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}"
dc.__repr__()
Out[29]: "{'y': 2, 'x': 1, 'z': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}"
More information about the Tutor
mailing list