tags:

views:

614

answers:

5

Hi! Is there a way in Python to override a class method at instance level? For example:

class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!

Thanks

+5  A: 

Yes, it's possible:

class Dog:
    def bark(self):
        print "Woof"

def new_bark(self):
    print "Woof Woof"

foo = Dog()

funcType = type(Dog.bark)

# "Woof"
foo.bark()

# replace bark with new_bark for this object only
foo.bark = funcType(new_bark, foo, Dog)

# "Woof Woof"
foo.bark()
codelogic
+2  A: 
class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF

# METHOD OVERRIDE
def new_bark():
    print "WoOoOoF!!"
boby.bark = new_bark

boby.bark() # WoOoOoF!!

You can use the boby variable inside the function if you need. Since you are overriding the method just for this one instance object, this way is simpler and has exactly the same effect as using self.

nosklo
IMHO using the original signature adds to readability, especially if the function is defined elsewhere in the code, not near the instance. The exception would be the case where the overriding method is also used independently as a function. Of course, in this simple example, it doesn't matter.
codelogic
A: 

Since functions are first class objects in Python you can pass them while initializing your class object or override it anytime for a given class instance:

class Dog:
    def __init__(self,  barkmethod=None):
        self.bark=self.barkp
        if barkmethod:
           self.bark=barkmethod
    def barkp(self):
        print "woof"

d=Dog()
print "calling original bark"
d.bark()

def barknew():
    print "wooOOOoof"

d1=Dog(barknew)
print "calling the new bark"
d1.bark()

def barknew1():
    print "nowoof"

d1.bark=barknew1
print "calling another new"
d1.bark()

and the results are

calling original bark
woof
calling the new bark
wooOOOoof
calling another new
nowoof
JV
+12  A: 

Please do not do this as shown. You code becomes unreadable when you monkeypatch an instance to be different from the class.

You cannot debug monkeypatched code.

When you find a bug in boby and print type(boby), you'll see that (a) it's a Dog, but (b) for some obscure reason it doesn't bark correctly. This is a nightmare. Do not do it.

Please do this instead.

class Dog:
    def bark(self):
        print "WOOF"

class BobyDog( Dog ):
    def bark( self ):
        print "WoOoOoF!!"

otherDog= Dog()
otherDog.bark() # WOOF

boby = BobyDog()
boby.bark() # WoOoOoF!!
S.Lott
A: 

Though I liked the inheritance idea from S. Lott and agree with the 'type(a)' thing, but since functions too have accessible attributes, I think the it can be managed this way:

class Dog:
    def __init__(self, barkmethod=None):
        self.bark=self.barkp
        if barkmethod:
           self.bark=barkmethod
    def barkp(self):
        """original bark"""
        print "woof"

d=Dog()
print "calling original bark"
d.bark()
print "that was %s\n" % d.bark.__doc__

def barknew():
    """a new type of bark"""
    print "wooOOOoof"

d1=Dog(barknew)
print "calling the new bark"
d1.bark()
print "that was %s\n" % d1.bark.__doc__

def barknew1():
    """another type of new bark"""
    print "nowoof"

d1.bark=barknew1
print "another new"
d1.bark()
print "that was %s\n" % d1.bark.__doc__

and the output is :

calling original bark
woof
that was original bark

calling the new bark
wooOOOoof
that was a new type of bark

another new
nowoof
that was another type of new bark
JV
If it needs to be "managed", then -- to me -- something's wrong. Especially when there's a first-class language feature that already does the job.
S.Lott