[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