3

I want to monkey patch a method of a library class to define a different default for a param. This fails:

from functools import partial

class A(object):
    def meth(self, foo=1):
        print(foo)

A.meth = partial(A.meth, foo=2)

a = A()
a.meth()

with:

Traceback (most recent call last):
  File "...", line 10, in <module>
    a.meth()
TypeError: meth() missing 1 required positional argument: 'self'

what is the correct way of doing this?

(Original code is using getattr on the method names in a loop)

The answers in the question linked involve defining a new module-level function - I would like to avoid a new function definition

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
  • Using `@override`? – Torxed Jan 31 '19 at 12:23
  • Possible duplicate of [Python: replacing a function within a class of a module](https://stackoverflow.com/questions/50599045/python-replacing-a-function-within-a-class-of-a-module) – Torxed Jan 31 '19 at 12:24
  • Oh I am not familiar with `@override` – Mr_and_Mrs_D Jan 31 '19 at 12:24
  • Ignore my override statement, that might be my brain mixing in some Java syntax.. ouff.. That declaration might just be eye-candy-fluff. Sorry for the confusion. You should be able to just in-line replace `A.meth = new_func` and it should work. – Torxed Jan 31 '19 at 12:27
  • Kind of surprises me why partial does not do the trick basically - I can always define a new function as in the question linked but would like to avoid it, out of curiosity – Mr_and_Mrs_D Jan 31 '19 at 12:28
  • I think Marjtein Peiters (I'm butchering his name at the moment) and some of the more deep-divers of Python can clarify why that isn't working as you intend. I just know how to get around the problems :) – Torxed Jan 31 '19 at 12:30
  • Seems to work if you instantiate `a` first and then do `a.meth = partial(a.meth, foo=1)` followed by `a.meth()`. Don't know whether that will solve your purpose – Mortz Jan 31 '19 at 12:30
  • @Mortz no I want to define it before instantiating A (due to those getattr calls in different places) – Mr_and_Mrs_D Jan 31 '19 at 12:32
  • 1
    @Mr_and_Mrs_D Note that `A.meth` is not a simple function, it is a descriptor. Hence you need to substitute it with an object that implements the descriptor protocol. – a_guest Jan 31 '19 at 12:37

1 Answers1

4

Use partialmethod:

In [32]: from functools import partialmethod

In [33]: A.meth = partialmethod(A.meth, foo=2)

In [34]: a = A()

In [35]: a.meth()
2
tayfun
  • 3,065
  • 1
  • 19
  • 23