On Fri, Jan 22, 2016 at 11:10:39PM -0600, boB Stepp wrote: > On Thu, Jan 21, 2016 at 5:49 AM, Steven D'Aprano <st...@pearwood.info> wrote:
> > class X: > > pass > > > > def func(this): > > print("instance %r called method" % this) > > > > X.method = func > > Am I understanding this correctly? It appears to me that you have > successfully added a method to class X from outside of class X! If > this is the case, then this clarifies some things I was wondering > about in my other thread. Yes, you are reading it correctly. Of course, in practice you wouldn't do that as shown. Why write the method outside the class when you could write it inside the class? There are some good reasons for doing something similar though: (1) Perhaps you have a whole family of classes that share the same method. Three traditional solutions to this are to use inheritence, a mixin class, or traits. But a fourth is to create your classes without the method, then dynamically add the extra, shared, method into each one afterwards. Possibly by using a simple decorator: def method(self, arg): ... def decorate(cls): cls.method = method return cls @decorate class Spam: ... This technique is even more powerful when the method you are injecting is *slightly different* each time. For that, you can use a closure, created *inside* the decorator function. Play around with this example and see if you can understand what is going on: # Warning: this may expand your mind. def decorate(number): # Create a closure over the number. def method(self, x): """Return x + %d.""" return x + number method.__doc__ %= number # Create a decorator. def decorator(cls): # Inject the method into the class. cls.method = method return cls # Return the decorator so it can be used. return decorator @decorate(5) class AddFive: pass @decorate(9) class AddNine: pass (2) Another reason for doing this may be that you have an existing class from some library that you have to use. You can't subclass it, because too much of your code already depends on using that specific class. In some languages, like Java, perhaps the library authors marked the class as unsubclassable. But you want to add a new method for your own use. Here's an example of this: http://stackoverflow.com/questions/13730924/java-adding-fields-and-methods-to-existing-class You'll notice that the answers given don't really solve the problem, apart from a vague and scary-sounding suggestion to use "byte-code injection". A number of people suggest subclassing, but a comment from another person says the the question also applies to him, but in his case subclassing isn't practical. In Python, we have two solutions: Write a function, and use that. Instead of calling obj.new_method(), we simply have new_function(obj). This option is available to Java as well, but hardly anyone ever thinks of it because Java is the Kingdom of Nouns: http://steve-yegge.blogspot.com.au/2006/03/execution-in-kingdom-of-nouns.html Or *monkey-patch* the class using a new method we create on the outside. https://en.wikipedia.org/wiki/Monkey_patch Monkey-patching is a powerful technique, but should be used with care. Overuse is considered harmful: http://devblog.avdi.org/2008/02/23/why-monkeypatching-is-destroying-ruby/ [...] > I guess I am trying to wrap my mind around this incredible power and > flexibility that Python provides. I thought I had asked a relatively > harmless question. But it generated some strong responses! It seemed > like "self" had a similar utility of use as "print" to me. After all, > we can't redefine "print", can we? But now I realize that I can do > exactly that if I so choose. That is both fascinating and scary! Indeed. And in Python 3, print is a regular function, which means it *can* be redefined by shadowing, or even by monkey-patching the built-in module. -- Steve _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor