On Jun 22, 7:36 pm, Steven D'Aprano <[EMAIL PROTECTED]> wrote: > On Fri, 22 Jun 2007 14:44:54 -0700, John Henry wrote: > > The above doesn't exactly do I what need. I was looking for a way to > > add method to a class at run time. > > > What does work, is to define an entire sub-class at run time. Like: > > > class DummyParent: > > def __init__(self): > > return > > > def method_static(self, text): > > print text > > return > > > text = "class Dummy(DummyParent):" > > text += "\n\t" + "def __init(self):" > > text += "\n\t" + "\tDummyParent.__init__(self)" > > text += "\n\t" + "def method_dynamic(self):" > > text += "\n\t" + "\tself.method_static(\"it's me\")" > > > exec text > > (By the way, you misspelled __init__.) > > The correct way to add methods to an instance is with the > instancemethod() function. > > class Parrot: > def __init__(self): > import new > # define a function > def method_dynamic(self, *args): > args.insert(0, "hello, it's me!") > return self.method_static(*args) > # convert it into an instance method > method = new.instancemethod(function, self, self.__class__) > # add it to self > self.method_dynamic = method > def method_static(self, text): > return text > > And here is how I use it: > > >>> p = Parrot() > >>> p.method_dynamic() # call from an instance > "it's me" > >>> Parrot.method_dynamic # does it exist in the class? > > Traceback (most recent call last): > File "<stdin>", line 1, in ? > AttributeError: class Parrot has no attribute 'method_dynamic' > > BUT, having said all that, are you sure this is what you want to do? This > is probably a better way to get the same results: > > class Parrot: > def __init__(self): > self.text = "hello, it's me!" > def method_dynamic(self): > return self.method_static(self.text) > def method_static(self, text): > return text > > Earlier in the thread, you said you wanted a CLASS method, which is very > different. You can use the classmethod built-in function (no need to > import new) to create class methods: > > class Parrot: > def method_dynamic(cls): > return cls.method_static(cls(), "hello it's me") > # or alternatively cls().method_static("hello it's me") > method_dynamic = classmethod(method_dynamic) > def method_static(self, text): > return text > > Note: if you are using recent versions of Python, instead of saying > "method = classmethod(method)" AFTER the block, you can use a decorator > before the block. > > Making method_dynamic a class method and calling an instance method is not > a good way of doing things, since the class method has to create a new > instance before calling method_static, only to throw it away afterwards. > That is wasteful and could be very expensive. > > A better way is to change your class so that method_static is a class > method too, especially since it doesn't use self: > > class Parrot: > @classmethod > def method_dynamic(cls): > return cls.method_static("hello it's me") > @classmethod > def method_static(cls, text): > return text > > (Actually, since method_static doesn't even use the class, you could use > staticmethod instead of classmethod. Remember to remove the "cls" argument.) > > Hope this helps, > > -- > Steven.
Thanks everybody for your responses. I know my terminology isn't quite exact. Hopefully that didn't confuse you too much. I used that example hoping to simplify the question. As you'll see below, it takes more if I have to explain the entire story. Of all the answers, I think the new.instancemethod is most appropriate. I'll try to explain: With a PythonCard application, if you want to have a button, normally you use the layout editor which creates a dictionary representing the button, and you would have a function for each of the events it has to handle. For instance, a simple one button ap might look like this: #!/usr/bin/python """ __version__ = "$Revision: 1.6 $" __date__ = "$Date: 2004/08/17 19:46:06 $" """ from PythonCard import model rsrc = {'application':{'type':'Application', 'name':'Minimal', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'Minimal PythonCard Application', 'size':(200, 100), 'components': [ {'type':'Button', 'name':'Button1', 'position':(5, 35), 'label':'Button1'}, ] # end components } # end background ] # end backgrounds } } class Minimal(model.Background): def on_initialize(self, event): pass def on_Button1_mouseClick(self, event): print "Clicked Button1" if __name__ == '__main__': app = model.Application(Minimal, None, rsrc) app.MainLoop() 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? With the application I have to come up with, I have a tree on the left, and then depending which branch the user clicks, I have to create various controls on the right. So, it becomes some what of a nightmare for me (since I have lots of branches and they are all quite different). Each time the use click a branch, I have to create the buttons, data entry-fields, and so forth on the fly - along with all of the functions to handle them. This is what I came up with so far (before reading your messages): #!/usr/bin/python """ __version__ = "$Revision: 1.6 $" __date__ = "$Date: 2004/08/17 19:46:06 $" """ from PythonCard import model rsrc = {'application':{'type':'Application', 'name':'Minimal', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'Minimal PythonCard Application', 'size':(200, 300), 'components': [ ] # end components } # end background ] # end backgrounds } } class Minimal(model.Background): def on_initialize(self, event): return nButtons = 7 text="class MinimalChild(Minimal):" text += "\n\t" + "def on_initialize(self, event):" text += "\n\t" + "\tMinimal.on_initialize(self,event)" for iButton in xrange(nButtons): name = "Button"+str(iButton+1) text += "\n\t" + "\tself.components['"+name+"'] = {" +\ "'type':'Button', " +\ "'name':'"+name+"', " +\ "'label':'"+name+"', "+\ "'position':(5, "+str(35+iButton*30)+")}" if iButton!=nButtons-1: text += "\n\t" + "def on_"+name+"_mouseClick(self, event):" exec(text) if __name__ == '__main__': app = model.Application(MinimalChild, None, rsrc) app.MainLoop() With this approach, each time I click a button, a new one gets created, along with a new handler for mouseClick of that new button. 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. Regards, -- http://mail.python.org/mailman/listinfo/python-list