__getattribute__ meta class?

Carl Banks pavlovevidence at gmail.com
Mon Feb 25 23:46:25 EST 2008


On Feb 25, 9:43 pm, "bambam" <da... at asdf.asdf> wrote:
> I have a class containing a series of classes like this:
>
> class Th(Externaldevice):
>   class _Communicate(commandset2.CommandSet_Communicate):
>     def __getattribute__(self,attrname):
>       attr =
> commandset2.CommandSet_Communicate.__getattribute__(self,attrname)
>       if "__call__" in dir(attr):
>         return functools.partial(Th._wrapper_function, self.parent, attr)
>       else:
>         return attr
>
>   class _System(commandset2.CommandSet_System):
>     def __getattribute__(self,attrname):
>       attr = commandset2.System_Communicate.__getattribute__(self,attrname)
>       if "__call__" in dir(attr):
>         return functools.partial(Th._wrapper_function, self.parent, attr)
>       else:
>        return attr
>
> That is, a a wrapper function is applied to a bunch of methods in a bunch of
> classes.
> The class declarations are simple, but even so, repetitive.
> Can anyone suggest a more compact representation for the class declarations?


Looks like you want a class factory here:


def create_wrapper_class(name,base):
    def getattribute(self,attrname):
        attr = base.__getattr__(self,attrname)
        if hasattr(attr,"__call__"):
            return functools.partial(Th._wrapper_function,
                                     self.parent, attr)
        return attr
    clsdict = { '__getattribute__': getattribute }
    return type(name,(base,),clsdict)

class Th(Externaldevice):
    _Communicate = create_wrapper_class('_Communicate',
        commandset2.CommandSet_Communicate)
    _System = create_wrapper_class('_System',
        commandset2.CommandSet_System)


The class factory calls type directly to create the class here rather
than using the class statement since the name can vary.  I took the
liberty of making a few improvements to the __getattribute__ function;
hasattr is a lot faster than building a list with dir, and the final
else was redundant.


> Also, because the parent class name is given explicitly in the class
> declarations, I can't over-ride the _wrapper_function in a child class,
> except by over-riding each of the class declarations. Is there a way to
> reference the _wrapper_function just to the containing class?

It looks like your wrapped classes have an attribute, self.parent,
that refers to the Th object in question.  It should be possible to
access its wrapper function directly then:

def create_wrapper_class(name,base):
    def getattribute(self,attrname):
        attr = base.__getattr__(self,attrname)
        if hasattr(attr,"__call__"):
            return functools.partial(
                self.parent._wrapper_function, attr)
        return attr
    clsdict = { '__getattribute__': getattribute }
    return type(name,(base,),clsdict)


Perhaps self.parent is not the Th in question, which could be the case
if _wrapper_function is a staticmethod.  In that case, you'd have to
pass it to the wrapper class somehow.

Presumably you have some other methods in Th that create instances of
these embedded classes.  I'm guessing your Th class has a __getattr__
(or properties) that does this when accessing attributes of Th?

What you'd normally do in cases like this is to modify the class's
constructor to accept the object.  For instance, if your __getattr__
looks like this:


def __getattr__(self,attr):
    if attr == 'System':
        return self._System()
    ...

then you could change it to look like this:

def __getattr__(self,attr):
    if attr == 'System':
        return self._System(self)
    ...


And then you'd change the _System class to accept and store the
argument passed to it.  That way your system class will be able to see
what object called it and figure out the appropriate type that way.


def create_wrapper_class(name,base):
    def init(self,thobject):
        self.thobject = thobject
    def getattribute(self,attrname):
        attr = base.__getattr__(self,attrname)
        if hasattr(attr,"__call__"):
            wrapper = self.thobject._wrapper_function
            return functools.partial(wrapper,self.parent,attr)
        return attr
    clsdict = { '__init__': init,
                '__getattribute__': getattribute }
    return type(name,(base,),clsdict)


That's some pretty advanced stuff you're doing there, chief.  My
examples probably wouldn't work out of the box, but hopefully it'll
give you enough ideas to do it.


Carl Banks



More information about the Python-list mailing list