Take a look at this code:
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value '!!!!!'
instance.func = new_func
print(instance.func())
This code creates an instance of SomeClass
, calls original func
, then overrides this function and calls it again.
I want to override a function in a single instance of a class, but not in the entire class so all the instances got the function overrided.
I expect this code to print:
Hello, World!
Hello, World!!!!!
But it prints:
Hello, World!
Traceback (most recent call last):
File "test.py", line 17, in <module>
print(instance.func())
TypeError: new_func() missing 1 required positional argument: 'self'
The self
argument is not passed to the overrided function. Why? Aren't SomeClass.func(instance)
and instance.func()
the same?
How to override the function correctly so I can access the self
argument in the overrided function?
CodePudding user response:
Well let's see
The func
of the original instance has type bound method
SomeClass().func
# <bound method SomeClass.func of <__main__.SomeClass object at 0x7f293e1cb3d0>>
and your func
has type function
instance.func
# <function __main__.new_func(self)>
The idea is to get a new method of some new class like this:
class SomeNewClass:
def new_func(self):
return self._value '!!!!!'
instance.func = SomeNewClass().new_func
instance.func
# <bound method SomeNewClass.new_func of <__main__.SomeNewClass object at 0x7f293e2825d0>>
But as you see, this is a method of the new class :(
By the way, if you don't initialize the class, the type will change to function
:
class SomeNewClass:
def new_func(self):
return self._value '!!!!!'
instance.func = SomeNewClass.new_func
instance.func
# <function __main__.SomeNewClass.new_func(self)>
So the next idea is to change the method before the initialization of a class:
SomeClass.func = new_func
instance = SomeClass()
instance.func
# <bound method new_func of <__main__.SomeClass object at 0x7f29441e4350>>
Seems good. The result based on your code:
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value '!!!!!'
SomeClass.func = new_func
instance = SomeClass()
print(instance.func())
# Hello, World!
# Hello, World!!!!!!
If you need to change the method of an instance and not of the class. There is also a way to do that using types.MethodType
:
import types
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value '!!!!!'
instance.func = types.MethodType(new_func, instance)
print(instance.func())
# Hello, World!
# Hello, World!!!!!!