Adding method to a class on the fly
Steven D'Aprano
steve at REMOVE.THIS.cybersource.com.au
Sat Jun 23 10:42:47 EDT 2007
On Sat, 23 Jun 2007 00:02:09 -0700, John Henry wrote:
[snip]
> Notice that the event handler for mouseClick to Button1 is done via
> the function on_Button1_mouseClick. This is very simple and works
> great - until you try to create the button on the fly.
>
> Creating the button itself is no problem. You simply do a:
>
> self.components['Button1'] = {'type':'Button',
> 'name':'Button1',
> 'position':(5, 35),
> 'label':'Button1'}
>
> But then how do I create the on_Button1_mouseClick function?
That depends on what it is supposed to do, but in general you want a
factory function -- a function that returns functions. Here's a simple
example:
def mouseclick_factory(arg):
def on_mouseClick(self, event):
print "You clicked '%s'." % arg
return on_mouseClick
func1 = mouseclick_factory("Button 1")
func2 = mouseclick_factory("this button")
func3 = mouseclick_factory("something")
Now let's try them out, faking the "self" and "event" parameters:
>>> func1(None, None)
You clicked 'Button 1'.
>>> func2(None, None)
You clicked 'this button'.
>>> func3(None, None)
You clicked 'something'.
Obviously in a real application, self and event are important and can't be
faked with None.
Now, there are two ways of using that factory function in a class. Here
is an example of both.
class Parrot:
def __init__(self, arg):
self.bar = mouseclick_factory(arg)
foo = mouseclick_factory("Foo")
p = Parrot("bar")
If you do it like this, there is a slight Gotcha to watch out for: as
provided, foo is an instance method (and so has the self argument
supplied automatically) but bar is not (and so needs the self argument to
be supplied manually.
>>> p.foo(None) # fake event argument
You clicked 'Foo'.
>>> p.bar(p, None) # self and fake event arguments
You clicked 'bar'.
If this is a problem -- and believe me, it will be -- you can use
new.instancemethod to convert bar.
[snip]
> Now, knowing the new.instancemethod way, may be I can simplify the
> above somewhat and improve the efficiencies but I still don't see how
> one can do it without using the exec function.
Rule 1:
Never use exec.
Exception for experts:
If you know enough to never need exec, you can use it.
Rule 1 is actually not quite true, but as an approximation to the truth,
it is quite good.
--
Steven.
More information about the Python-list
mailing list