I'm trying to monkeypatch a method on SomeClass
from an imported package:
from somepackage import SomeClass
def newmethod(obj, node, **kwargs):
""" """
SomeClass.oldmethod = newmethod
Where obj
and node
are in the default call signature of SomeClass.oldmethod
:
class SomeClass(object):
def oldmethod(obj, node):
""" """
I'm aware that monkeypatching is not good practice, but we need a workaround while we fix some issues that otherwise can't be tackled. The above approach works FINE, but we'd like to use partial functions to do this. For example:
from functools import partial
newmethod_a = partial(newmethod, foo='a')
newmethod_b = partial(newmethod, foo='b')
The partial function is being called because we need to pass different **kwargs. But when I try to overload now:
SomeClass.oldmethod = newmethod_a
I get an error related to the number of arguments passed, but it's very specific to my problem so pasting it might not be helpful... The error I think is related to the call signature of oldmethod
taking two positional arguments (obj, node
), and my partial functions aren't passing a reference to the obj
and node
correctly. I've tried different constructions like:
newmethod_a = partial(SomeClass.newmethod, foo='a')
I'm sorry that I can't produce a minimal working example. I hoped maybe an expert would just recognize this issue from experience and tell me if what I'm attempting is even possible within the scope of partial
.
Thanks
Here's a quick example:
from functools import partial
class foo(object):
def bar(self, pos1, **kwargs):
print("bar got self=%r, pos1=%r, kwargs=%r" % (self, pos1, kwargs))
foo.bar = partial(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Fails...
This fails with a TypeError
. The reason for this is that baz.bar
is a bound method which expects its first argument to be a foo
instance, but that the partial
object is not, and hence Python will not add self
for you when you call baz.bar
. (This is not entirely correct, but the true reason is quite technical. See the Descriptor How-To linked below.) Calling baz.bar(baz, 1)
would work. To work around this, you'll have to make foo.bar
a method again:
import types
# In Python 2:
foo.bar = types.MethodType(partial(foo.bar.__func__, qux=1), None, foo)
# Method that is compatible with both Python 2 and 3:
foo.bar = types.MethodType(partial(foo.bar, qux=1), foo)
# Python 3 only:
from functools import partialmethod
foo.bar = partialmethod(foo.bar, qux=1)
baz = foo()
baz.bar(1) # Works!
See also:
Loosely related, on functions vs. methods and when/how methods are bound:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With