views:

1746

answers:

7

In Java you can define a new class inline using anonymous inner classes. This is useful when you need to rewrite only a single method of the class.

Suppose that you want create a subclass of OptionParser that overrides only a single method (for example exit()). In Java you can write something like this:

new OptionParser () {

    public void exit() {
        // body of the method
    }
};

This piece of code creates a anonymous class that extends OptionParser and override only the exit() method.

There is a similar idiom in Python? Which idiom is used in these circumstances?

+10  A: 

Java uses anonymous classes mostly to imitate closures or simply code blocks. Since in Python you can easily pass around methods there's no need for a construct as clunky as anonymous inner classes:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff)

Edit: I'm aware that this is not what is needed in this special case. I just described the most common python solution to the problem most commonly by anonymous inner classes in Java.

Joachim Sauer
-1 I want to subclass optparse.OptionParser() not pass around method references.
Andrea Francia
In that case what's the problem with writing a real subclass? I was merely illustrating the most common use of anonymous inner classes.
Joachim Sauer
+1: Anonymous inner classes are a way for Java to lighten up on the complex syntax. Python already has simple syntax and doesn't need anonymous classes to lighten up the load.
S.Lott
I known that Python is "better" but the answer is about passing method references while the question is about subclassing and overriding a single method.
Andrea Francia
I wouldn't say that Python is better. Every language has its strength. Passing around callable code is simply easier to do in Python than in Java. And I know that you are searching for something else, I keep my answer here in case someone else finds your question and is looking for what I provide.
Joachim Sauer
@saua: That's right. I can't no more up vote, stackoverflow says that "This vote is too old to be undone or changed".
Andrea Francia
@Andrea: nevermind the downvote. No problem at all.
Joachim Sauer
+2  A: 

In python you have anonymous functions, declared using lambda statement. I do not like them very much - they are not so readable, and have limited functionality.

However, what you are talking about may be implemented in python with a completely different approach:

class a(object):
  def meth_a(self):
    print "a"

def meth_b(obj):
  print "b"

b = a()
b.__class__.meth_a = meth_b
Roberto Liffredo
Right track, but this does not work. File "t", line 12, in <module> b.meth_a()TypeError: meth_b() takes exactly 1 argument (0 given)
gnud
Right: to change a method of an object, you have to change it to its metaclass. I have updated the code.
Roberto Liffredo
b.__class__.meth_a = meth_bDoes this code affects all objects based on "a" class or only the "b" object?
Andrea Francia
Best to ask that as a separate question so the answers get votes
James Hopkin
I think the question can be answered much better by simply playing at the interactive shell.This is one of the major advantages for python: have a doubt or question on a language feature? ok play with it in the sjhell and see if it is valid.
Roberto Liffredo
+5  A: 

Python probably has better ways to solve your problem. If you could provide more specific details of what you want to do it would help.

For example, if you need to change the method being called in a specific point in code, you can do this by passing the function as a parameter (functions are first class objects in python, you can pass them to functions, etc). You can also create anonymous lambda functions (but they're restricted to a single expression).

Also, since python is very dynamic, you can change methods of an object after it's been created object.method1 = alternative_impl1, although it's actually a bit more complicated, see gnud's answer

hasen j
You actually can't replace methods this way -- see my answer for the proper way.
gnud
+8  A: 

You can accomplish this in three ways:

  1. Proper subclass (of course)
  2. a custom method that you invoke with the object as an argument
  3. (what you probably want) -- adding a new method to an object (or replacing an existing one).

Example of option 3 (edited to remove use of "new" module -- It's deprecated, I did not know ):

import types
class someclass(object):
    val = "Value"
    def some_method(self):
        print self.val

def some_method_upper(self):
    print self.val.upper()

obj = someclass()
obj.some_method()

obj.some_method = types.MethodType(some_method_upper, obj)
obj.some_method()
gnud
Short of making a named inner class and instantiating it (which may be preferable for readability), option 3 seems like a good way to do this.
Greg Case
yes -- that's why I wrote "What you probably want". I just put it last because the post text flows better that way -- and I wanted to enumerate the options.
gnud
why are you using new? it is deprecated since quite a long time
Roberto Liffredo
since we are overwriting a previously defined method and the new temporarily named method (some_method_upper) is never used, why not use a lambda and make it inline since it will be more consistent with anonymous inline classes.
fuentesjr
not sure but maybe something like: obj.some_method = types.MethodType(lambda self: print self.val.upper(), obj)
fuentesjr
Of course -- in this trivial example, this can be done. The example merely demonstrates how to replace one method with another -- in a real-life example, a lambda might be suboptimal.
gnud
@fuentesjr: You can't use `print` in lambdas if Python version < 2.6
J.F. Sebastian
+5  A: 

Well, classes are first class objects, so you can create them in methods if you want. e.g.

from optparse import OptionParser
def make_custom_op(i):
  class MyOP(OptionParser):
    def exit(self):
      print 'custom exit called', i
  return MyOP

custom_op_class = make_custom_op(3)
custom_op = custom_op_class()

custom_op.exit()          # prints 'custom exit called 3'
dir(custom_op)            # shows all the regular attributes of an OptionParser

But, really, why not just define the class at the normal level? If you need to customise it, put the customisation in as arguments to __init__.

(edit: fixed typing errors in code)

John Fouhy
Thanks, but I don't understand the line custom_op = custom_op_class(). Should it be removed?
Andrea Francia
make_custom_op() returns a class. You have to call the class to create an instance, which is what that line does. However, there were a couple of bugs in my code on the last two lines, which I have now fixed, in case they were confusing you.
John Fouhy
This is a simple but powerful technique that, when used properly (not just as a hack), can make for very elegant code.
Daniel
+5  A: 

Python doesn't support this directly (anonymous classes) but because of its terse syntax it isn't really necessary:

class MyOptionParser(OptionParser):
    def exit(self, status=0, msg=None):
        # body of method

p = MyOptionParser()

The only downside is you add MyOptionParser to your namespace, but as John Fouhy pointed out, you can hide that inside a function if you are going to do it multiple times.

davidavr
A: 

You can use the type(name, bases, dict) builtin function to create classes on the fly. For example:

op = type("MyOptionParser", (OptionParser,object), {"foo": lambda self: "foo" })
op().foo()

Since OptionParser isn't a new-style class, you have to explicitly include object in the list of base classes.

Joe Hildebrand