If I understand, you want something like this:
class SubDevice(object):
def __init__(self, action):
self.action = action
def action1():
print "Hello!"
def action2():
print "Goodbye!"
sd1 = SubDevice(action1)
sd2 = SubDevice(action2)
sd1.action()
sd2.action()
>>>
Hello!
Goodbye!
Now, I'm not sure where the variable parameter list would come into play. It seems to me that if you want a transparent interface, then you have to make the parameter list consistent. Can you give an example of what you had in mind?
Hope it helps,
Jeff
jrcagle
Practically a Master Poster
608 posts since Jul 2006
Reputation Points: 92
Solved Threads: 156
Huh. There's something funky here that I don't understand. Because I don't have the module functools, I simplified a bit:
class SubDevice(object):
def __init__(self, action):
#always pass a reference to self as first argument
self.action = action # functools.partial(action, self)
self.state = "ready"
def action1(self): #the argument list has to contain self!
if self.state == "ready":
self.state = "error"
else:
self.state = "ready"
a = SubDevice(action1)
a.action() #### <---
print a.state # 'error'
Shockingly, this throws an error:
Traceback (most recent call last):
File "C:/Python24/subdevicetest.py", line 14, in -toplevel-
a.action()
TypeError: action1() takes exactly 1 argument (0 given)
Now, my understanding of the paradigm was that a.action() called the member method with a as the first parameter. Yet ... it doesn't!
When I replace with:
class SubDevice(object):
def __init__(self, action):
#always pass a reference to self as first argument
self.action = action # functools.partial(action, self)
self.state = "ready"
def action1(self): #the argument list has to contain self!
if self.state == "ready":
self.state = "error"
else:
self.state = "ready"
a = SubDevice(action1)
a.action(a) ### <----
print a.state # 'error'
Then it works fine. So yes, I think there is an issue with what you want to do, and no, I don't (yet) know what it is.
Vega, thoughts?
Jeff
jrcagle
Practically a Master Poster
608 posts since Jul 2006
Reputation Points: 92
Solved Threads: 156
Followup -- here's a quote from Yoda himself :
What exactly happens when a method is called? You may have noticed that x.f() was called without an argument above, even though the function definition for f specified an argument. What happened to the argument? Surely Python raises an exception when a function that requires an argument is called without any--even if the argument isn't actually used ...
Actually, you may have guessed the answer: the special thing about methods is that the object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method's object before the first argument.
So Guido thinks your code oughta work. :) Something funky is going on here. Or I'm not thinking straight. LOL
BTW, the clean way to do what you want is this:
class SubDevice(object):
def __init__(self, action):
#always pass a reference to self as first argument
self.action = lambda : action(self)
self.state = "ready"
def action1(self): #the argument list has to contain self!
if self.state == "ready":
self.state = "error"
else:
self.state = "ready"
a = SubDevice(action1)
a.action()
print a.state # 'error'
Jeff
jrcagle
Practically a Master Poster
608 posts since Jul 2006
Reputation Points: 92
Solved Threads: 156
Ah. Many regards to Matthew Dixon Cowles over at Python-help, who says,
Dear Jeff,[INDENT]> Hi,
[/INDENT]Hello![INDENT]> I was trying to assist someone who wants to hook methods into
> objects post-instantiation.
[/INDENT][INDENT]> I'm really confused. I thought that a.action() automatically
> passed a as the first parameter.[/INDENT]You can stick a Python function pretty much anywhere:[INDENT][INDENT][INDENT]>>> def f():
[/INDENT][/INDENT][/INDENT]... print "wibble"
...[INDENT][INDENT][INDENT]>>> l=[f]
>>> l[0]()
[/INDENT][/INDENT][/INDENT]wibble
But making a function an attribute of an object doesn't automatically
make it a method:[INDENT][INDENT][INDENT]>>> class c:
[/INDENT][/INDENT][/INDENT]... pass
...[INDENT][INDENT][INDENT]>>> o=c()
>>> o.x=f
>>> o.x()
[/INDENT][/INDENT][/INDENT]wibble
There, f is a plain function that's an attribute.
To make a function into an instance's method, you need the
instancemethod() function of the new module:[INDENT][INDENT][INDENT]>>> def m(self):
[/INDENT][/INDENT][/INDENT]... print "wibble"
...[INDENT][INDENT][INDENT]>>> import new
>>> o.m=new.instancemethod(m,o,c)
>>> o.m()
[/INDENT][/INDENT][/INDENT]wibble
Regards,
Matt
There it is. Following this lead, your code could become:
import new
class SubDevice(object):
def __init__(self, action):
#always pass a reference to self as first argument
self.action = new.instancemethod(action,self,SubDevice)
self.state = "ready"
def action1(self): #the argument list has to contain self!
if self.state == "ready":
self.state = "error"
else:
self.state = "ready"
a = SubDevice(action1)
a.action()
print a.state # 'error'
and that works.
I would not have predicted that... LOL
Jeff
jrcagle
Practically a Master Poster
608 posts since Jul 2006
Reputation Points: 92
Solved Threads: 156