20

I am trying to run all the functions in my class without typing them out individually.

class Foo(object):
    def __init__(self,a,b):
        self.a = a
        self.b=b

    def bar(self):
        print self.a

    def foobar(self):
        print self.b

I want to do this but with a loop, because my actual class has about 8-10 functions.

x = Foo('hi','bye')
x.bar()
x.foobar()
cardamom
  • 6,873
  • 11
  • 48
  • 102
collarblind
  • 4,549
  • 13
  • 31
  • 49

6 Answers6

15

You can use dir() or __dict__ to go through all of an object's attributes. You can use isinstance() and types.FunctionType to tell which ones are functions. Just call any that are functions.

Update

As Tadhg commented, inspect.ismethod seems like the best choice. Here's some example code:

import inspect
from itertools import ifilter


class Foo(object):
    def foo1(self):
        print('foo1')

    def foo2(self):
        print('foo2')

    def foo3(self, required_arg):
        print('foo3({!r})'.format(required_arg))

f = Foo()
attrs = (getattr(f, name) for name in dir(f))
methods = ifilter(inspect.ismethod, attrs)
for method in methods:
    try:
        method()
    except TypeError:
        # Can't handle methods with required arguments.
        pass
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • 2
    might as well check for any [`callable`](https://docs.python.org/2/library/functions.html#callable)s or use [`inspect.ismethod`](https://docs.python.org/2/library/inspect.html#inspect.ismethod) – Tadhg McDonald-Jensen May 06 '16 at 15:13
  • I'd forgotten about the `inspect` module, @TadhgMcDonald-Jensen, thanks. – Don Kirkby May 06 '16 at 16:23
  • 4
    with python 3 not need anymore of itertools. ifilter became filter and it is in the core library. – Zioalex Jan 11 '18 at 15:50
  • [This](https://stackoverflow.com/a/1911287/6301103) is a much simpler way to do it. Also uses the inspect module. – jaaq Feb 01 '19 at 10:35
10

This is the easiest way to solve this problem, also it's kind of flexible to do changes in it.

import threading
from threading import Thread

class ClassName():
    def func1(self):
        print ('2')

    def func2(self):
        print ('3')

    def runall(self):
        if __name__ == '__main__':
            Thread(target = self.func1).start()
            Thread(target = self.func2).start()
run = ClassName()
run.runall() # will run all the def's in the same time
Karam Qusai
  • 713
  • 12
  • 16
  • How do I do this so that the class is executed in the order that it is written and not in the order of the time that it takes to execute? For example, I am doing some data sorting and one portion of the data sorting takes faster than the other and prints faster but I need the other portion to be done first. – George Adams Feb 23 '21 at 01:16
  • Maybe I am msising something but op asks for a way to do this wtihout explicitly having to write all function calls manually and this answer does not really show that. – RogerKint Jan 26 '23 at 13:57
9

You can get list of all 'public' methods of your instance:

x = Foo('hi','bye')

public_method_names = [method for method in dir(x) if callable(getattr(x, method)) if not method.startswith('_')]  # 'private' methods start from _
for method in public_method_names:
    getattr(x, method)()  # call

See more about getattr Actually, Python doesn't have public or private semantic, you can read that if interested

Community
  • 1
  • 1
Viach Kakovskyi
  • 1,487
  • 1
  • 14
  • 21
2

While I realize it's not what you're asking, I think what you're asking (execute all methods) in general is a bad idea, because the object's API is not internal to the object. (E.g. the user has to write functionality (namely exactly the functionality that you're asking for) in order to use the class.)

You're much better off defining a list of methods that you want to run yourself. E.g.:

exec_methods = ["bar", "foobar"]
for method in exec_methods:
    getattr(x, method)()
acdr
  • 4,538
  • 2
  • 19
  • 45
2

While I do not particularly recommend calling all the methods on an object since as soon as you add some that require an argument it will obviously fail, you could use a decorator to label the methods that represent a test case and then search for all the ones that have said label:

def tester_method(f):
    f._is_for_test = True #add an arbitrary attribute to the function, completely supported for exactly this reason.
    return f

def call_all_tester_methods(x):
    """finds all attributes with a ._is_for_test attribute of their 
own and calls all of them in no guaranteed order"""
    methods = {}
    for name in dir(x):
        attr = getattr(x,name)
        if getattr(attr,"_is_for_test",False):
            methods[name] = attr
    for name,method in methods.items():
        #print("calling: {}".format(name))
        method()

class Foo(object):
    def __init__(self,a,b):
        self.a = a
        self.b=b

    @tester_method
    def bar(self):
        print(self.a)

    @tester_method
    def foobar(self):
        print(self.b)

    def othermethod_not_for_test(self,arg):
        return self.a + arg #this is not included in the test case

obj = Foo('hi','bye')
call_all_tester_methods(obj)
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
0

I understand this question is very old and I am adding this solution as another idea for people like me which want to do something like this on a built in class. If you are looking to iterate over a class, including one you are not writing yourself, such as a built in class. This code takes the built in class platform and runs each method and/or shows you the output of the variable.

import platform
dir_without_underscores = [method for method in dir(platform) if not method.startswith('_')]

for method_name in dir_without_underscores:
    actual_method = eval(f'platform.{method_name}') # convert to actual callable name
    try:
        if callable(actual_method):
            print(f"{method_name}() -->  {actual_method()}")
        else:
            print(f"{method_name} --> {actual_method}")
    except:
        continue
userJB
  • 1