__getattribute__ meta class?

B

bambam

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?
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?

Steve
 
C

Carl Banks

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
 
G

grflanagan

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?
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?

Steve

No real idea what you're doing, but surely altering the class at
creation-time, rather than on each attribute call, would be a better
approach? Here's one idea (sorry if misunderstood your problem):

[code python]
import inspect

def wrapped(func):
def wrapper(self, arg):
return func(self, self.parent + ': ' + arg)
return wrapper

class Meta(type):

def __new__(cls, name, bases, attrs):
for key, val in attrs.iteritems():
if inspect.isfunction(val) and not key.startswith('_'):
attrs[key] = wrapped(val)
return super(Meta, cls).__new__(cls, name, bases, attrs)

class Base(object):
__metaclass__ = Meta
parent = 'root'

def foo(self, s):
return s.upper()

def bar(self, s):
return s.lower()

b = Base()

print b.foo('apple')
print b.bar('PEAR')
print
b.parent = 'firstchild'

print b.foo('apple')
print b.bar('PEAR'
[/code]

ROOT: APPLE
root: pear

FIRSTCHILD: APPLE
firstchild: pear

Gerard
 
B

bambam

Thank you both.

If I understand correctly, I have two new ways to creating my new classes:

class _Communicate(commandset2.CommandSet_Communicate):
__metaclass__ = My_meta

or
_Communicate = create_wrapper_class
|('_Communicate',commandset2.CommandSet_Communicate)

and also two new ways to check for callable methods :~)

hasattr(attr,"__call__")
or
inspect.isfunction(attr)


Gerard points out that I can re-define the callable methods instead of using
dynamic over-ride at each method call. It's left as an exercise for the
reader
to determine the behaviour of derived classes :~)

Carl points out that unless the methods are required to be static methods,
I can use a wrapper function from the parent object, instead of a wrapper
function from the parent class. And I can use a variable for my
wrapper_function
base class: self, or self.parent

Two new words are introduced: 'type' and 'super'. ...That part is still
opaque to me... I also don't know why the example meta class is derived
from 'type'.


The project is to interchangeably replace an object with a similar group of
objects. The original project was not built with this in mind: there is
no-one
here qualified to design that kind of project. So I'm retrofitting the
original
model by modification. Successive attempts have involved more and more
complex modifications. In retrospect, the project has three parts: remove
side effects, push side effects to a common location, modify code so that
changes only affect areas that encapsulate side effects. This code allows
top level code to pretend that the intermediate code has not changed.

regards
(david)
 
C

Carl Banks

In retrospect, the project has three parts: remove
side effects, push side effects to a common location, modify code so that
changes only affect areas that encapsulate side effects. This code allows
top level code to pretend that the intermediate code has not changed.

Gah.

Libraries that "helpfully" do things on behalf of the user strike
again, and the mess bambam posted is what you have to do to disable
these "helpful" effects.

I'll grant that it's possible that the library wasn't trying to be
helpful and was just indicriminately letting side effects loose.

Shame on the writer in any case.


Carl Banks
 
B

bambam

Carl Banks said:
Gah.

Libraries that "helpfully" do things on behalf of the user strike
again, and the mess bambam posted is what you have to do to disable
these "helpful" effects.

I'll grant that it's possible that the library wasn't trying to be
helpful and was just indicriminately letting side effects loose.

Shame on the writer in any case.


Carl Banks


(smile). The hardware has been implemented in a conversational style:
you ask a question, something happens, you get a response. It's only
when you try the conversational style in a lecture theatre that you realise
the constraints.

Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top