Dynamic generation of methods for a class from a list of names

There is a class with the following structure:

class MyClass1:
    def verb_function(self, verb, *args, **kwargs):
        return do_something(verb, *args, **kwargs)

    def verba(self, *args, **kwargs):
        return self.verb_function('verba', *args, **kwargs)

    def verbb(self, *args, **kwargs):
        return self.verb_function('verbb', *args, **kwargs)

    def verbc(self, *args, **kwargs):
        return self.verb_function('verbc', *args, **kwargs)

So we have many functions that all do essentially the same thing with different command verbs.
My use case is calling a CLI excutable with more than 60 possible verbs.
This means the current implementation contains a long passage of repeating code that defines all the method functions for the verbs.

Is there a more compact way to express this in Python?

I was thinking about something like this:

class MyClass2:
    verbs = ['verba', 'verbb', 'verbc']

    def verb_function(self, verb, *args, **kwargs):
        return do_something(verb, *args, **kwargs)


for verb in MyClass2.verbs:
    setattr(MyClass2, verb, MyClass2.verb_function)

Obviously this code doesn’t work.
I think we’d need something more complicated instead of this simple setattr() call.
Maybe this can be done with functions from the inspect module and/or decorators?

I played around with this, but the closest I got was that I was able to call verb_function by the other names, but it didn’t know that it was called by this name (eg. inspect.currentframe().f_code.co_name always returned "verb_function" instead of "verba").

Is there a standard approach to this kind of problem that I didn’t find?

I’m not 100% sure I understand your problem exactly, but I think this will solve your problem:

from functools import partial

class MyClass:
    def verb_function(self, verb, *args, **kwargs):
        print(verb, args, kwargs)

    def __getattr__(self, name):
        if name.startswith("verb"):
            return partial(self.verb_function, verb=name)
        else:
            raise AttributeError

I don’t know if this is a good solution but, it could work!

>>>from functools import partialmethod
>>> def set_verb_method(cls):
...     verbs = ['verba', 'verbb', 'verbc']
...     for method in verbs:
...             setattr(cls,method,partialmethod(cls.verb_func, method))
...     return cls
>>> @set_verb_method
... class MyClass:
...     def verb_func(self,verb, *args, **kwargs):
...             print(f'Hello, Im {verb} and this are my args {args} and kwargs {kwargs}')
>>> mc = MyClass()
>>> mc.verba()
Hello, Im verba and this are my args () and kwargs {}
>>> mc.verba(10)
Hello, Im verba and this are my args (10,) and kwargs {}
>>> mc.verba(10, z='Hello', w='World')
Hello, Im verba and this are my args (10,) and kwargs {'z': 'Hello', 'w': 'World'}
>>> mc.verbb(10, z='Hello', w='World')
Hello, Im verbb and this are my args (10,) and kwargs {'z': 'Hello', 'w': 'World'}
1 Like

Thanks to both of you for pointing me in the direction of partial functions.
I wasn’t aware of this concept and it’s working great!

I am using the method with the class decorator - another concept I didn’t really understand before :slight_smile:

The only thing that’s not so nice about this:
Now my IDE (PyCharm) doesn’t recognize the existence of the verb methods any more, which means they are not part of the recommendations any more.

Does anyone have any idea if there is a way to fix this?

dir(MyClass) already returns all the methods, but it seems that is not what PyCharm uses to generate the list.