fantabolous
fantabolous

Reputation: 22726

Override all class methods at once to do the same thing

I'm using a 3rd party API that provides a single Python wrapper class which contains ~50 methods that do nothing except accepting a set of arbitrary parameters. I am then meant to make my own class and override each of those methods to do what I actually want. My issues with this:

Stripped down version of their class:

class TheirWrapper:
    def __init__(self):
        pass
    def func1(self, a, b, c):
        pass
    def func2(self, d, e, f):
        pass
    ... and ~50 more

And stripped down version of what I have working:

class MyWrapper:
    def addToQueue(self, localvars):
        # adds calling function name and localvars to queue (after removing self from localvars)
    def func1(self, a, b, c):
        self.addToQueue(locals())
    def func1=2(self, d, e, f):
        self.addToQueue(locals())
    ... and ~50 more

Considering that I do precisely the same thing in each overridden method (self.addToQueue(locals())), I would like to be able to override ALL of their methods at once (except __init__) to do that one thing. Is such a thing possible?

Upvotes: 4

Views: 1051

Answers (1)

sanyassh
sanyassh

Reputation: 8550

Here is a possible way to do it using inspection of contents of TheirWrapper with dir():

import inspect


class TheirWrapper:
    def __init__(self):
        pass
    def func1(self, a, b, c):
        pass
    def func2(self, d, e, f):
        pass


class MyWrapper:
    def addToQueue(self, localvars):
        # your implementation
        print(localvars)


### You can orginize this block into decorator or metaclass and make more general
def add_func(func_name):
    def add(self, *args, **kwargs):
        signature = inspect.signature(getattr(TheirWrapper, func_name))
        bind = signature.bind(self, *args, **kwargs)
        arguments = dict(bind.arguments)
        arguments['func_name'] = func_name
        self.addToQueue(arguments)
    return add


for name in dir(TheirWrapper):
    if not name.startswith('__'):
        setattr(MyWrapper, name, add_func(name))
###

w = MyWrapper()
w.func1(1, 2, 3)
# prints {'self': <__main__.MyWrapper object at 0x00000000030262E8>, 'a': 1, 'b': 2, 'c': 3, 'func_name': 'func1'}

docs for inspect.signature & bind

docs for dir

Upvotes: 4

Related Questions