Override a method at instance level

Python

Python Problem Overview


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!!

Python Solutions


Solution 1 - Python

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)

foo.bark()
# "Woof Woof"

Solution 2 - Python

You need to use MethodType from the types module. The purpose of MethodType is to overwrite instance level methods (so that self can be available in overwritten methods).

See the below example.

import types

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

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

def _bark(self):
    print "WoOoOoF!!"

boby.bark = types.MethodType(_bark, boby)

boby.bark() # WoOoOoF!!

Solution 3 - Python

To explain @codelogic's excellent answer, I propose a more explicit approach. This is the same technique that the . operator goes thorough to bind a class method when you access it as an instance attribute, except that your method will actually be a function defined outside of a class.

Working with @codelogic's code, the only difference is in how the method is bound. I am using the fact that functions and methods are non-data descriptors in Python, and invoking the __get__ method. Note particularly that both the original and the replacement have identical signatures, meaning that you can write the replacement as a full class method, accessing all the instance attributes via self.

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

def new_bark(self): print "Woof Woof"

foo = Dog()

"Woof"

foo.bark()

replace bark with new_bark for this object only

foo.bark = new_bark.get(foo, Dog)

foo.bark()

"Woof Woof"

By assigning the bound method to an instance attribute, you have created a nearly complete simulation of overriding a method. One handy feature that is missing is access to the no-arg version of super, since you are not in a class definition. Another thing is that the __name__ attribute of your bound method will not take the name of the function it is overriding, as it would in class definition, but you can still set it manually. The third difference is that your manually-bound method is a plain attribute reference that just happens to be a function. The . operator does nothing but fetch that reference. When invoking a regular method from an instance on the other hand, the binding process creates a new bound method every time.

The only reason that this works, by the way, is that instance attributes override non-data descriptors. Data descriptors have __set__ methods, which methods (fortunately for you) do not. Data descriptors in the class actually take priority over any instance attributes. That is why you can assign to a property: their __set__ method gets invoked when you try to make an assignment. I personally like to take this a step further and hide the actual value of the underlying attribute in the instance's __dict__, where it is inaccessible by normal means exactly because the property shadows it.

You should also keep in mind that this is pointless for magic (double underscore) methods. Magic methods can of course be overridden in this way, but the operations that use them only look at the type. For example, you can set __contains__ to something special in your instance, but calling x in instance would disregard that and use type(instance).__contains__(instance, x) instead. This applies to all magic methods specified in the Python data model.

Solution 4 - Python

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.

Solution 5 - Python

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!!

Solution 6 - Python

Since no one is mentioning functools.partial here:

from functools import partial

class Dog:
    name = "aaa"
    def bark(self):
        print("WOOF")

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

def _bark(self):
    print("WoOoOoF!!")

boby.bark = partial(_bark, boby)
boby.bark() # WoOoOoF!!

Solution 7 - Python

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

Solution 8 - Python

Be careful when you need to call the old method inside the new method:

import types

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

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

def _bark(self):
  self.bark()
  print("WoOoOoF!!")

boby.bark = types.MethodType(_bark, boby)

boby.bark() # Process finished with exit code -1073741571 (0xC00000FD) [stack overflow]
# This also happens with the  '__get__' solution

For these situations, you could use the following:

def _bark(self):
  Dog.bark(self)
  print( "WoOoOoF!!") # Calls without error

But what if someone else in the library already overrode foo's bark method? Then Dog.bark(foo) is not the same as foo.bark! In my experience, the easiest solution that works in both of these cases is

# Save the previous definition before overriding
old_bark = foo.bark
def _bark(self):
  old_bark()
  print("WoOoOoF!!")
foo.bark = _bark
# Works for instance-overridden methods, too

Most of the time, subclassing and using super is the correct way to handle this situation. However, there are times where such monkeypatching is necessary and will fail with a stack overflow error unless you are a bit more careful.

Solution 9 - Python

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

Solution 10 - Python

Dear this is not overriding you are just calling the same function twice with the object. Basically overriding is related to more than one class. when same signature method exist in different classes then which function your are calling this decide the object who calls this. Overriding is possible in python when you make more than one classes are writes the same functions and one thing more to share that overloading is not allowed in python

Solution 11 - Python

I found this to be the most accurate answer to the original question

https://stackoverflow.com/a/10829381/7640677

import a

def _new_print_message(message):
    print "NEW:", message

a.print_message = _new_print_message

import b
b.execute()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpistacchioView Question on Stackoverflow
Solution 1 - PythoncodelogicView Answer on Stackoverflow
Solution 2 - PythonHarshal DhumalView Answer on Stackoverflow
Solution 3 - PythonMad PhysicistView Answer on Stackoverflow
Solution 4 - PythonnoskloView Answer on Stackoverflow
Solution 5 - PythonS.LottView Answer on Stackoverflow
Solution 6 - Pythonuser1285245View Answer on Stackoverflow
Solution 7 - PythonJV.View Answer on Stackoverflow
Solution 8 - PythonntjessView Answer on Stackoverflow
Solution 9 - PythonJV.View Answer on Stackoverflow
Solution 10 - PythonnagimsitView Answer on Stackoverflow
Solution 11 - PythonRuvalcabaView Answer on Stackoverflow