[Tutor] question about __copy__ and __deepcopy__

Albert-Jan Roskam sjeik_appie at hotmail.com
Fri Apr 15 05:48:24 EDT 2016


> From: oscar.j.benjamin at gmail.com
> Date: Thu, 14 Apr 2016 21:34:39 +0100
> Subject: Re: [Tutor] question about __copy__ and __deepcopy__
> To: sjeik_appie at hotmail.com
> CC: tutor at python.org
> 
> On 14 April 2016 at 20:38, Albert-Jan Roskam <sjeik_appie at hotmail.com> 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 don't know about your copy/deepcopy stuff. It looked fine to me but
> I'm not very experienced in that area. I wonder what this mutable
> namedtuple is for though.
> 
> Looking at it:
> 
> > class Record(dict):
> >
> >     def __init__(self, *args, **kwargs):
> >         super(Record, self).__init__(*args, **kwargs)
> >         self.__dict__ = self
> 
> It's not so much a mutable namedtuple as an "attribute dict". It's a
> dict whose keys can be accessed as attributes - because it is its own
> instance dict. Of course it also has dict attributes like pop, items
> etc. (see dir(dict) for a list). The reason that dicts use d[k] rather
> than d.k for accessing keys is to be able to store arbitrary keys
> without conflicting with the dict's methods which are attributes.
> 
> A namedtuple is something very different. It subclasses tuple and the
> whole idea is that an instance is lightweight (not having an attribute
> dict) and hashable and imutable etc. A mutable version of that might
> just look like:
> 
> class Point(object):
>     # No instance dict:
>      __slots__ = ['x', 'y']
> 
>     def __init__(self, x, y):
>         self.x = x
>         self.y = y
> 
> It depends what you really want it for though.

HI Oscar, 

Ok, I agree that "mutable namedtuple" is a misnomer. I started using a regular namedtuple, and then I wanted something with similar functionality, but with the possibility to update/mutate the fields. The AttrDict was the option I liked. The order of the fields is rarely important in my case. I can easily use the AttrDict with SqlAlchemy, too. What I like about both namedtuple and AttrDict is attribute lookup: that makes code so, so, soooo much easier to read. This seems to be a nice generalization of your code:

class Point(object):
    
    def __init__(self, **kwargs):
        Point.__slots__ = kwargs.keys()
        for k, v in kwargs.items():
            setattr(self, k, v)
        
point = Point(x=1, y=2, z=3)
print point.x
point.x = 42
print point.x


I have no experience with __slots__ (but I think I roughly know what it's for). I expected this to fail:

point.remark = "booh"

point
Out[36]: <__main__.Point at 0x7f282de9ccd0>

point.remark
Out[37]: 'booh'

How can it be that __slots__ may be extended once the Point class has been instantiated?

(sorry if this post is a bit long --this is just so much fun!) If I add a convenience getter/setter, the setter does indeed only seem to work for attributes that were in __slots__ already (here "z")

class Point(object):
    
    def __init__(self, **kwargs):
        Point.__slots__ = kwargs.keys()
        for k, v in kwargs.items():
            setattr(self, k, v)
            
    @property
    def values(self):
        return {attr: getattr(self, attr) for attr in Point.__slots__}
    @values.setter
    def values(self, d):
        for attr, value in d.items():
            print "setting", attr, value
            setattr(self, attr, value)

        
point = Point(x=1, y=2, z=3)
print point.x
point.x = 42
print point.x
print point.values
point.values = dict(a=1, b=2, c=3)
print point.values  ## no a, b, c here!
point.values = dict(a=1, b=2, z=444)
print point.values   # z is updated, though!


Thank you!

Albert-Jan

 		 	   		  


More information about the Tutor mailing list