Adding properties to an instance
Jared Grubb
jared.grubb at gmail.com
Wed Feb 6 15:46:54 EST 2008
Er, instead of "getattr(self,...) you gotta do
"object.__getattr__(self,...)" and same for setattr and delattr. Dumb error
on my part. (Otherwise you get infinite recursion!)
On Feb 6, 2008 12:43 PM, Jared Grubb <jared.grubb at gmail.com> wrote:
> Here's one way of doing what you're asking... I would suggest using
> __getattribute__ and __setattr__ to dispatch the methods to the custom class
> you invent that holds all those properties.
>
> For example (I simplified your makeprops into __init__ just to keep the
> example short, but you can probably see the idea here..)
>
> class A(object):
> def __init__(self, **kw):
> class _PropHolder(object):
> pass
> for k,v in kw.items():
> setattr(_PropHolder, k, property(fget=itemgetter(k)))
> self._custom_props = _PropHolder()
> def __getattribute__(self, attr):
> try:
> return getattr(self._custom_props, attr)
> except AttributeError:
> return getattr(self, attr)
> def __setattr__(self, attr, val):
> if hasattr(self._custom_props, attr):
> setattr(self._custom_props, attr, val)
> else:
> setattr(self, attr, val)
> def __delattr__(self, attr):
> if hasattr(self._custom_props, attr):
> delattr(self._custom_props, attr)
> else:
> delattr(self, attr)
>
>
>
>
> On 6 Feb 2008, at 12:06, dg.google.groups at thesamovar.net wrote:
>
> Hi all,
>
> So I understand that properties belong to a class not an instance, but
> nonetheless I want to add properties to an instance. I have a class
> which when an instance is created runs some fairly complicated code
> and produces a set of names which I'd like to be able to access via
> properties. At the moment, I'm using something like obj.getvar(name)
> but I'd like to be able to write obj.name. (Note that they can't be
> just standard attributes because they only get computed when they are
> accessed.) I could generate functions like obj.name() but I want it to
> be obj.name instead.
>
> The solution I've come up with is to create a new class for each
> object which is just the real class with some extra properties, and
> then dynamically change the class of the object to this new class.
> This seems to work, but I wonder if (a) there is a nicer solution than
> the one I'll post below, (b) if there are any dangers or pitfalls of
> this approach. The obvious difficulty is with derived classes. At the
> moment, I'm insisting that a derived class has to call a makeprops()
> method to create the properties.
>
> It's kind of similar to this recipe:
>
> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/197965
>
> but that recipe has a much simpler situation in which the properties
> and values are known at the time of the creation of the object (by
> contrast, I don't know what the properties are until the end of the
> __init__ method).
>
> Any thoughts?
>
> Code below to illustrate my approach.
>
> import warnings
> from operator import itemgetter
>
> class A(object):
> def __init__(self,**kwds):
> self._kwds = kwds
> self.makeprops()
> def __getitem__(self,i):
> return self._kwds[i]
> def makeprops(self):
> if not hasattr(self,'_madeprops'):
> self._madeprops = set()
> self._failedprops = set()
> class _A(self.__class__):
> pass
> for k,v in self._kwds.items():
> if not k in self._madeprops and k in dir(self):
> if not k in self._failedprops:
> warnings.warn("Cannot create property "+k+",
> already used in object "+str(self),RuntimeWarning)
> self._failedprops.add(k)
> else:
> setattr(_A,k,property(fget=itemgetter(k)))
> self._madeprops.add(k)
> self.__class__ = _A
>
> class B(A):
> def __init__(self,**kwds):
> super(B,self).__init__(**kwds)
> self.makeprops()
>
> class C(A):
> def __init__(self,**kwds):
> self._kwds = kwds
>
> a = A(x=1)
> b = B(x=2,makeprops=3)
> c = C(x=3)
> print isinstance(a,A), isinstance(a,B), isinstance(a,C) # True False
> False
> print isinstance(b,A), isinstance(b,B), isinstance(b,C) # True True
> False
> print isinstance(c,A), isinstance(c,B), isinstance(c,C) # True False
> True
> print a.__class__ # <class '__main__._A'>
> print b.__class__ # <class '__main__._A'>
> print c.__class__ # <class '__main__.C'>
> print a.x # 1
> print b.x # 2
> print b.makeprops # <bound method _A.makeprops of <__main__._A object
> at 0x00A86810>>
> try:
> print c.x # raises exception
> except AttributeError:
> print "c has no element x"
> c.makeprops()
> print c.x # 3
> print a.__class__ # <class '__main__._A'>
> print b.__class__ # <class '__main__._A'>
> print c.__class__ # <class '__main__._A'>
>
> ---
> Dan Goodman
> http://thesamovar.net/contact
> --
> http://mail.python.org/mailman/listinfo/python-list
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20080206/3df1a838/attachment-0001.html>
More information about the Python-list
mailing list