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!!
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!!
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!!
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"
funcType
does and why it is necessary. –
Dander funcType = types.MethodType
(after importing types
) instead of funcType = type(Dog.bark)
. –
Subrogate __get__
on the function to bind it to the instance. –
Sianna __get__
also works in Python 3. –
Subclavian tmp=foo.bark; foo.bark=funcType(new_bark, foo, Dog); foo.bark(); foo.bark=tmp
–
Odin TypeError: method expected 2 arguments, got 3
on the foo.bark =
assignment. Works fine without including the class as a third argument. –
Estragon foo.__class__
rather than Dog
as an input for funcType
, as you don't always have the class definition in your scope –
Sepulcher 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!!
Cannot assign to a method
see related issue. for now, the workaround is to use setattr(boby, "bar", types.MethodType(_bark, boby)
–
Clymer __get_item__
which didn't work properly: https://mcmap.net/q/175808/-overriding-special-methods-on-an-instance –
Meridith 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.
super().bark()
? –
Funky <pre>
tags are the only way to mix code blocks with other formatting. Triple backticks and indentation do not support this. –
Sianna foo.bark = new_bark.__get__(foo, foo.__class__)
rather than foo.bark = new_bark.__get__(foo, Dog)
. You don't always have the class name in your scope, e.g., when you get your object from a "factory"-like function, rather than an explicit constructor. So it is more robust. –
Sepulcher 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
.
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 tryolabs.com/blog/2013/07/05/run-time-method-patching-python (examples) - no I'm not affiliated with the linked site or author. –
Welch 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!!
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!!
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
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.
If you try to "wrap" the base method you will get {RecursionError}maximum recursion depth exceeded in comparison
error.
To resolve this use self.__class__.method
instead of self.method
In [21]: import types
...:
...:
...: class Dog:
...: def bark(self):
...: print("WOOF")
...:
...:
...: def my_bark(self):
...: print("RRRR")
...: self.__class__.bark(self)
...:
...:
...: dog = Dog()
...: dog.bark = types.MethodType(my_bark, dog)
...: dog.bark()
...:
RRRR
WOOF
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
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
I found this to be the most accurate answer to the original question
https://mcmap.net/q/175809/-override-module-method-where-from-import-is-used
import a
def _new_print_message(message):
print "NEW:", message
a.print_message = _new_print_message
import b
b.execute()
© 2022 - 2024 — McMap. All rights reserved.
boby.bark = YOUR_NEW_FUNCTION.__get__(boby)
will do it. Make sure that your new function accepts aself
argument. – Sepulcher