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