1

I have a list of methods and I can call all of the methods at once with another method.

How can I call the method which contains all while leaving out certain items(or methods) from the list? I can currently specify one to leave out. I am not sure how to leave out more than one. Here is what I am working with:

class SomeClass:
    def method_a(self):
        print('method_a')

    def method_b(self):
        print('method_b')

    def method_c(self):
        print('method_c')

    def method_runner(self, skip_name='' ):
        for m in [self.method_a, self.method_b, self.method_c]:
            if m.__name__ != skip_name:
                m()

Now I can do this:

>>> some_obj = SomeClass()
>>> some_obj.method_runner('')
method_a
method_b
method_c
>>> some_obj.method_runner('method_a')
method_b
method_c
>>> some_obj.method_runner('method_b')
method_a
method_c

Is there a way to do something like this?

class SomeClass:
    def method_a(self):
        print('method_a')

    def method_b(self):
        print('method_b')

    def method_c(self):
        print('method_c')

    def method_runner(self, skip_name='', skip_name2='', skip_name3=''):
        for m in [self.method_a, self.method_b, self.method_c]:
            options = [skip_name, skip_name2, skip_name3]
            for o in options:
                if m.__name__ != o:
                    m()

And specify more than one method to get an outcome such as:

>>> some_obj.method_runner('method_a', 'method_c')
method_b
Kade Williams
  • 1,041
  • 2
  • 13
  • 28

2 Answers2

2

You can do this:

def method_runner(self, *skip_list):
        for m in [self.method_a, self.method_b, self.method_c]:
            if m.__name__ not in skip_list:
                m()

The * means varying number of arguments.

If you do not want to type the method names manually, you can use this:

def method_runner(self, *skip_list):
    methods = [f for f in map(lambda x: getattr(self,x), dir(self)) if callable(f) and f.__name__ != 'method_runner']
    for m in methods:
        if m.__name__ not in skip_list:
            m()
mshsayem
  • 17,557
  • 11
  • 61
  • 69
2

Yes, there are at least to straightforward approaches. The most straightforward is for the parameter accept a container of objects to skip:

def method_runner(self, skipnames):
    for m in [self.method_a, self.method_b, self.method_c]:
        if m.__name__ not in skipnames:
            m()

And you would call by passing an appropriate container (in this case a set but a list or tuple might do):

SomeClass().method_runner({'method_a', 'method_c'})

But it sounds like you'd rather use variable-length arguments:

def method_runner(self, *skipnames):
    for m in [self.method_a, self.method_b, self.method_c]:
        if m.__name__ not in skipnames:
            m(self)

Which you could then call like this:

SomeClass().method_runner('method_a', 'method_c')

However, skipnames will now always be a tuple, which might not have the performance characteristics you require.

As recommended by @ChristianDean you may want to make your list of methods a class variable:

In [7]: class SomeClass:
   ...:     def method_a(self):
   ...:         print('method_a')
   ...:
   ...:     def method_b(self):
   ...:         print('method_b')
   ...:
   ...:     def method_c(self):
   ...:         print('method_c')
   ...:
   ...:     _my_methods = method_a, method_b, method_c
   ...:
   ...:     def method_runner(self, skipnames):
   ...:         for m in self._my_methods:
   ...:             if m.__name__ not in skipnames:
   ...:                 m(self)
   ...:

In [8]: SomeClass().method_runner({'method_a', 'method_c'})
method_b

Just note, you'd have to pass self to the function manually, because it is not a method!

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • @KadeWilliams in a function definition signature, means [variable number arguments](https://stackoverflow.com/questions/3394835/args-and-kwargs) – juanpa.arrivillaga Mar 21 '18 at 04:38
  • 1
    +1 I would also recommend making the list `[self.method_a, self.method_b, self.method_c]` a class variable. One can then avoid wasting time reconstructing the same list each time `method_runner` is called. – Christian Dean Mar 21 '18 at 04:40
  • 2
    You can trivially turn your tuple into a set if performance is a concern. How many methods can a class have though? – Mad Physicist Mar 21 '18 at 04:47
  • @MadPhysicist yes, likely it won't make an appreciable difference either way. – juanpa.arrivillaga Mar 21 '18 at 04:47