2

There were other stackoverflow questions similar to this, but is not specific to my problem where I need to override a function.

I want to convert the following Java code into Python:

import Someclass;

Someclass obj = new Someclass("stringarg") {
    @Override
    void do(x) {
      // Do extra stuff on function
      super.do(x);
    }
}

Do I need to explicitly create a dummy class for this? Can this be converted into Python just in a single statement like this Java code?

Used: Python 2.7.6, Java 1.8

P.S. This is to be done in Jython, where Someclass is an imported Java library.

Any help would be appreciated. Thanks.

UDPATE:

  • For those who have same problems as mine, but the import class is an abstract class:

Thanks to DNA's link, I managed to make it work by also just adding a super statement in his method like the following:

    def patch(self, x):
       # do something
       print 'goodbye'
       super(Someclass, self).do(x)

    obj = type('DummySomeclass', (Someclass, object), {"do": patch})("hello")
  • For those whose import class is not abstract, either DNA and algrebe's code works already but also just adding the missing super:

    ...
    super(Someclass, self).do(x)
    
Community
  • 1
  • 1
Jay-Ar Polidario
  • 6,463
  • 14
  • 28

2 Answers2

2

If you want to override/patch the method for a specific object (rather than at the class level, as described in algrebe's answer), you can do this, but you need to take care that the method is correctly bound, as described in this article

Here's a runnable example:

import types

class Someclass():

  def __init__(self, x):
    self.x = x

  def do(self):
    print self.x

if __name__ == "__main__":

  def patch(self):
    print "goodbye"

  obj = Someclass("hello")
  obj.do  = types.MethodType(patch, obj)

  obj.do()    # prints "goodbye"
DNA
  • 42,007
  • 12
  • 107
  • 146
  • I think this is what I am looking for. But can you modify def patch in such a way that it also accepts arguments (from my example it is arg 'x'). I am just not too familiar with Python yet. Thanks. – Jay-Ar Polidario Mar 27 '15 at 10:54
  • Implementing this in my code, I just found out now after trying this that Someclass was actually an 'abstract' class. And it is giving me an error "TypeError: can't instantiate abstract class" in line: obj = Someclass("hello"); Do you know how to work around this? – Jay-Ar Polidario Mar 27 '15 at 11:05
  • 1
    You'll need to either create a named subclass, or an anonymous subclass, as described in [this question](http://stackoverflow.com/questions/357997/does-python-have-something-like-anonymous-inner-classes-of-java) – DNA Mar 27 '15 at 12:02
  • I will accept this answer as I didn't specify in my question that the import class was actually an abstract class. And by just purely running this in my console, it produced the desired result without only the super part in which I just added by using def patch(self, x): print "goodbye" super(Someclass, self).do(x) # added – Jay-Ar Polidario Mar 27 '15 at 12:32
1

If I've understood correctly, you have a class with methods and you need to override a function, without inheriting this class and overriding it. Monkey Patching is one way to go about it.

As per Jython Concurrency

Your code may be different, but Python gives you good tools to avoid action at a distance. You can use closures, decorators, even sometimes selectively monkey patching modules. Take advantage of the fact that Python is a dynamic language, with strong support for metaprogramming, and remember that the Jython implementation makes these techniques accessible when working with even recalcitrant Java code.

class SomeClass(object):
    def __init__(self):
        self.a = "a"

    def foo(self):
        print "Base Foo"

    def bar(self):
        print "Base bar"
# new foo should execute something and then call the existing one
# i take it this is why you needed "super"
oldfoo = SomeClass.foo
def newFoo(self, name="default name"):
    print "Overridden %s" % name
    oldfoo(self)

# completely replace bar
def newBar(self):
    print "Overridden bar"

SomeClass.foo = newFoo
SomeClass.bar = newBar

obj = SomeClass()
obj.foo()
obj.bar()
Community
  • 1
  • 1
algrebe
  • 1,621
  • 11
  • 17
  • How do you call the super in the def do? – Jay-Ar Polidario Mar 27 '15 at 11:14
  • My Java is a little rusty, but I'm assuming you would want super only because you think of the @override as it creating a new class inheriting SomeClass for you, and overriding that method. But really, what you want to do is just call the existing function right ? I've updated my answer for it. Hope this helps – algrebe Mar 27 '15 at 15:29
  • If you do need to super some actual base classes that SomeClass inherits from, all you need is the class name and the self object, which you have access to anyway, newFoo("self" <-- this guy has the parameter required for you to call super from inside. – algrebe Mar 27 '15 at 15:32
  • Hey, you know what. I love you!! Particularly your line of code oldfoo(self). I scoured bunch and bunch of code in the internet about using super, and all they say is super(SomeClass, self).themethod(somearg). Some even say to change SomeClass depending on the inherited class. But in all my attempts, I always get an infinite loop inside the overriden function. I tried changing super(SomeClass,self) into a super(BaseClass,eslf), and even a super(BaserClass, self), but they all still loop! Thank you so much bro! It's not looping anymore! :D – Jay-Ar Polidario Mar 27 '15 at 15:57