122

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!!
Serenity
  • 35,289
  • 20
  • 120
  • 115
pistacchio
  • 56,889
  • 107
  • 278
  • 420

11 Answers11

191

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"
Undo
  • 25,519
  • 37
  • 106
  • 129
codelogic
  • 71,764
  • 9
  • 59
  • 54
  • 1
    A small comment, when you do funcType(new_bark, foo, Dog) its adding the name == bark and instance method Dog.new_bark in foo.__dict__ right ? So, when you call again it first lookup into the instance dictionary and call for that, – James Sapam Nov 29 '13 at 02:23
  • 18
    Please explain what this does, especially what `funcType` does and why it is necessary. – Aleksandr Dubinsky Jul 13 '16 at 04:30
  • 3
    I think this can be made a bit simpler and more explicit by using `funcType = types.MethodType` (after importing `types`) instead of `funcType = type(Dog.bark)`. – Elias Zamaria Nov 05 '16 at 23:28
  • 28
    I guess this does not work with Python 3. I am getting a "TypeError: function() argument 1 must be code, not function" error. Any suggestions for Python 3? – Sait Dec 16 '16 at 15:36
  • 2
    You can also call `__get__` on the function to bind it to the instance. – Mad Physicist Oct 15 '17 at 15:23
  • @Sait The solution of Mad Physicist using `__get__` also works in Python 3. – BlenderBender May 14 '18 at 14:42
  • This is almost what I actually need for my situation, but I would also like to not touch or change anything in the instance that I am overriding. Is that possible in any way? – 1313e May 01 '19 at 06:05
  • @1313e yes, you can make the override *local*: `tmp=foo.bark; foo.bark=funcType(new_bark, foo, Dog); foo.bark(); foo.bark=tmp` – Alex Cohn Jan 15 '20 at 13:47
  • 1
    On Python 3.7.11 I got `TypeError: method expected 2 arguments, got 3` on the `foo.bark = ` assignment. Works fine without including the class as a third argument. – nonethewiser Sep 11 '21 at 20:59
76

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!!
snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
Harshal Dhumal
  • 1,259
  • 1
  • 10
  • 18
  • 1
    if using python typing, mypy raises the error `Cannot assign to a method` [see related issue](https://github.com/python/mypy/issues/2427). for now, the workaround is to use `setattr(boby, "bar", types.MethodType(_bark, boby)` – jkr Jan 21 '21 at 12:40
  • 1
    This should be the accepted answer. It works well in both Python 2&3 – link89 Feb 16 '23 at 09:01
  • I tried overriding `__get_item__` which didn't work properly: https://stackoverflow.com/a/10376655/1417053 – Cypher Mar 12 '23 at 12:02
53

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.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • 5
    This should be the accepted answer: it's clean and works in Python 3. – BlenderBender May 14 '18 at 14:43
  • @BlenderBender. I appreciate your support – Mad Physicist May 14 '18 at 14:49
  • 1
    What is the difference between this answer and the one above yours from @Harshal Dhumai? – 1313e May 01 '19 at 06:22
  • 1
    @1313. Functionally, there shouldn't be much difference. I suspect the answer above may accept a wider range of callables as input, but without reading the docs and playing around, I'm not sure. – Mad Physicist May 01 '19 at 10:34
  • Python 2 docs for this: https://docs.python.org/2/howto/descriptor.html#functions-and-methods . So theoretically it's the same as @Harshal Dhumai's answer. – Rockallite May 14 '19 at 02:24
  • What would you propose to do if I want to wrap the original bark method and call it in the new method, like one would do with `super().bark()`? – Whadupapp Jul 27 '21 at 15:50
  • @Whadupapp. That may merit its own question. I'm not sure exactly what you're asking, so you would have to come up with a complete example. – Mad Physicist Jul 27 '21 at 19:15
  • @djvg. Please don't deliberately mess up my choice of formatting. – Mad Physicist Aug 04 '21 at 13:05
  • @MadPhysicist: sorry about that. I wasn't aware it was a deliberate choice of formatting. Thought it was some leftover style from the old days. Only trying to help. – djvg Aug 04 '21 at 14:12
  • @djvg. I appreciate the spirit in which the edit was made. Unfortunately `
    ` tags are the only way to mix code blocks with other formatting. Triple backticks and indentation do not support this.
    – Mad Physicist Aug 04 '21 at 19:03
28
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
  • 217,122
  • 57
  • 293
  • 297
  • 1
    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 Dec 27 '08 at 08:15
  • 1
    I don't understand why this isn't the accepted answer. It is called `patching` and this is the correct way to do it (e.g. `boby = Dog()` and `boby.bark = new_bark`). It is incredibly useful in unit *testing* for controls. For more explanation see https://tryolabs.com/blog/2013/07/05/run-time-method-patching-python/ (examples) - no I'm not affiliated with the linked site or author. – Geoff Sep 20 '16 at 21:45
  • 5
    new_bark method do not have access to self (instance) so there is no way user can access instance properties in new_bark. Instead one need to use MethodType from types module (see my answer below). – Harshal Dhumal Feb 10 '17 at 07:50
16

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
  • 384,516
  • 81
  • 508
  • 779
  • 9
    @arivero: I thought the "Please do not do this as shown" made that perfectly clear. What other or different words would you like to see to make it more clear that this is not answering the question which was asked, but is providing advice on why it's a bad idea? – S.Lott Jan 27 '12 at 19:39
  • 55
    I do not disagree in the advice, nor the OP as it seems. But I assume that people has reasons to ask. Or even if the OP hasn't, other future visitors could. So, IMHO, an answer plus a reprimand is better that just a reprimand. – arivero Jan 28 '12 at 22:17
  • 15
    @arivero: That didn't answer my question. – S.Lott Jan 29 '12 at 00:18
  • 9
    @S.Lott I think you should link the "shown" to the actual answer, I don't really have a problem with this being the accepted answer but there are reasons why you need to monkey patch in some circumstances and from my skim reading I took "as shown" to mean what you were showing, rather than a different answer. – Daniel Chatfield Sep 06 '13 at 16:05
  • Alright, for the sake of argument: let's say you've got twenty thousand instances of some class that took all night to instantiate. Now you've edited one of the methods of the base class. You want to use the new method, but don't want to wait to instantiate all those objects again. I am not sure in this case that any subclassing would be necessary. – Darren Ringer Aug 11 '16 at 15:31
  • 5
    Subclassing is a much stronger contract than monkey-patching a method. When possible, strong contracts prevent unexpected behaviour. But in some cases, a looser contract is desirable. In those situations, I would prefer using a callback -- instead of monkey-patching -- because, by allowing some behaviour to be customized, the class contract remains unviolated. Your answer, though practical advice, is quite poor for this question and your coding style is inconsistent. – Aaron3468 Sep 06 '16 at 11:51
  • MethodType from types module solves this problem (see my answer below). – Harshal Dhumal Feb 10 '17 at 07:56
  • 1
    Overriding at the instance level is very useful when you want a particular instance to behave differently. No need to write subclassing etc. This should not be accepted solution. Many other solutions below. – giwyni Jul 21 '18 at 18:32
  • 1
    Never say Never. There is probably always a good reason to do what the questioner asked. – shrewmouse Sep 07 '18 at 17:44
  • 2
    You said, "You cannot debug monkeypatched code." Eclipse and PyDev can debug it just fine. – shrewmouse Sep 24 '18 at 18:36
  • This does not answer the question at all. This shows how to override an inherited method at CLASS level. The OP is asking for overriding a method at INSTANCE level (when the class has already been initialized). I am currently in the same situation where I want do just that, as overriding inherited methods at class level is not an option. – 1313e May 01 '19 at 06:00
12

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!!
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
user1285245
  • 423
  • 3
  • 9
0

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.
  • 2,658
  • 4
  • 24
  • 36
0

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.

ntjess
  • 570
  • 6
  • 10
-4

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

nagimsit
  • 3
  • 1
-4

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.
  • 2,658
  • 4
  • 24
  • 36
  • 2
    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 Dec 27 '08 at 14:37
-4

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()
Community
  • 1
  • 1
Ruvalcaba
  • 445
  • 1
  • 4
  • 9