[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