Monkey-patch Python class
import module
class ReplaceClass(object):
....
module.MyClass = ReplaceClass
Monkey patching a class in another module in Python
The following should work:
import thirdpartymodule_a
import thirdpartymodule_b
def new_init(self):
self.a = 43
thirdpartymodule_a.SomeClass.__init__ = new_init
thirdpartymodule_b.dosomething()
If you want the new init to call the old init replace the new_init()
definition with the following:old_init = thirdpartymodule_a.SomeClass.__init__
def new_init(self, *k, **kw):
old_init(self, *k, **kw)
self.a = 43
Monkeypatching a Python class
You can monkey-patch methods onto a class, but it’s done like this:
B.stt_m = staticmethod(lambda x: say('stt_m', x))
B.cls_m = classmethod(lambda x: say('cls_m', x))
B.obj_m = lambda x: say('obj_m', x)
Your version for B.cls_m
is OK, but your B.stt_m
creates a normal method, and your B.obj_m
attaches an instance method to a newly created B()
, but then that B()
is thrown away, and you test a new B()
without the extra method.There’s usually no need to use types.MethodType
in Python:
types.MethodType(function, object_)
is equivalent tofunction.__get__(object_)
which is a bit better, although also very rare.Also (irrelevant but too neat not to mention), in newish versions of Python, your
print('*', msg, 'x =', x, 'type(x) =', type(x))
can just be written asprint(f"* {msg} {x = } {type(x) = }")
Monkeypatch method of instance from class with __slots __
>>> class X():
... __slots__ = ("a",)
... def func():
... print("1")
...
>>> x = X()
>>> type(x)
<class '__main__.X'>
>>> type(x).func = lambda self: print("2")
>>> x.func
<bound method <lambda> of <__main__.X object at 0x7f27fb88b050>>
>>> x.func()
2
>>>
Explanation: you have to monkeypatch the Runtime class instead of the instance. Monkey-patching class with inherited classes in Python
You need to explicitly overwrite the tuple of base classes in a.AA
, though I don't recommend modifying classes like this.
>>> import a
>>> class B:
... def foo(self):
... print(2)
...
>>> a.AA.__bases__ = (B,)
>>> a.AA().foo()
2
This will also be reflected in a.A.__subclasses__()
(although I am not entirely sure as to how that works; the fact that it is a method suggests that it computes this somehow at runtime, rather than simply returning a value that was modified by the original definition of AA
).It appears that the bases classes in a class
statement are simply remembered, rather than used, until some operation needs them (e.g. during attribute lookup). There may be some other subtle corner cases that aren't handled as smoothly: caveat programmator.
How does one use pytest monkeypatch to patch a class
tested this, works for me:
def test_thing(monkeypatch):
def patched_g(self, value):
return value * 2
monkeypatch.setattr(A, 'g', patched_g)
b = B()
assert b.f(2) == 4
python monkey patch a new class and import it
This is because of the import system.
Reading through the doc, you can find this paragraph:
[...] the statementThe problem is: what doesfrom spam.ham import eggs, sausage as saus
results in_temp = __import__('spam.ham', globals(), locals(), ['eggs', 'sausage'], 0)
eggs = _temp.eggs
saus = _temp.sausage
__import__()
does?TheSo, when you re-import the module, your customization will be lost.import
statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope. [...]A direct call to
__import__()
performs only the module search and, if found, the module creation operation.
To ensure it stays on, you can import numpy as np
and then, when using np
- after you assing this new class - you can always access wrong_add
.
>>> import numpy as np
>>> np.random.wrong_functions = wrong_functions
>>> np.random.wrong_function.wrong_add(1, 1)
3
EDIT: If you need/want to just call wrong_add
instead of full package path to function, you can always assign it to a variable.>>> wrong_add = np.random.wrong_function.wrong_add
>>> wrong_add(2, 2)
5
Can you monkey-patch built in classes and if not, how do I overload an operator to define addition for two different classes?
As for your first question: it's essentially impossible to alter built-in classes. Although you can mess with other classes that is generally a terrible idea. Instead, you can make a subclass that has the property that you want.
For example:
class mystr(str):
def __add__(self, other):
return mystr(str(self) + str(other))
This code inherits all properties from the str
class, except for the one we want to change, namely its addition behavior. By casting self
to str
we still delegate to str
's addition, but we also cast the other argument to str
to get the behavior you described.Finally, we cast back to mystr
so that we don't end up with a str
.
Now we can do the following:
>>> some_string = mystr("abc")
>>> some_string + 4
"abc4"
Related Topics
Detect File Change Without Polling
Does 'Anaconda' Create a Separate Pythonpath Variable for Each New Environment
Importerror: Cannot Import Name Numpy_Mkl
How to Fix Selenium Webdriverexception: the Browser Appears to Have Exited Before We Could Connect
How to Query Multiindex Index Columns Values in Pandas
Does Python Evaluate If's Conditions Lazily
Python Element-Wise Tuple Operations Like Sum
How to Set a Proxy for Phantomjs/Ghostdriver in Python Webdriver
Rename Multiindex Columns in Pandas
How to Define a Class Constant Inside an Enum
Errors While Building/Installing C Module for Python 2.7
Importing Class from Another File
How to Change Any Data Type into a String
Vectorized Numpy Linspace for Multiple Start and Stop Values
Apt Command Line Interface-Like Yes/No Input
Saving Plots (Axessubplot) Generated from Python Pandas with Matplotlib's Savefig