Is There A Way To Loop Through And Execute All Of The Functions In A Python Class?
Solution 1:
def assignOrder(order):
@decorator
def do_assignment(to_func):
to_func.order = order
return to_func
return do_assignment
class Foo():
@assignOrder(1)
def bar(self):
print "bar"
@assignOrder(2)
def foo(self):
print "foo"
#don't decorate functions you don't want called
def __init__(self):
#don't call this one either!
self.egg = 2
x = Foo()
functions = sorted(
#get a list of fields that have the order set
[
getattr(x, field) for field in dir(x)
if hasattr(getattr(x, field), "order")
],
#sort them by their order
key = (lambda field: field.order)
)
for func in functions:
func()
That funny @assignOrder(1)
line above def bar(self)
triggers this to happen:
Foo.bar = assignOrder(1)(Foo.bar)
assignOrder(1)
returns a function that takes another function, changes it (adding the field order
and setting it to 1
) and returns it. This function is then called on the function it decorates (its order
field gets thus set); the result replaces the original function.
It's a fancier, more readable and more maintainable way of saying:
def bar(self):
print "bar"
Foo.bar.order = 1
Solution 2:
No. You can access Foo.__dict__
, and call each value in turn (catching errors for non-callable members), but the order is not preserved.
for callable in Foo.__dict__.values():
try:
callable()
except TypeError:
pass
This assumes none of the functions take parameters, as in your example.
Solution 3:
Since Python stores the methods (and other attributes) of a class in a dictionary, which is fundamentally unordered, this is impossible.
If you don't care about order, use the class's __dict__
:
x = Foo()
results = []
for name, method in Foo.__dict__.iteritems():
if callable(method):
results.append(method(x))
This also works if the function takes extra parameters - just put them after the instance of the class.
Solution 4:
So long as you're only interested in Python 3.x (and from the empty parentheses in your class statement I'll guess you might be), then there is actually a simple way to do this without decorators: Python 3 allows you to provide your own dictionary like object to use while the class is defined.
The following code is from PEP3115 except for the last couple of lines which I added to print out the methods in order:
# The custom dictionary
class member_table(dict):
def __init__(self):
self.member_names = []
def __setitem__(self, key, value):
# if the key is not already defined, add to the
# list of keys.
if key not in self:
self.member_names.append(key)
# Call superclass
dict.__setitem__(self, key, value)
# The metaclass
class OrderedClass(type):
# The prepare function
@classmethod
def __prepare__(metacls, name, bases): # No keywords in this case
return member_table()
# The metaclass invocation
def __new__(cls, name, bases, classdict):
# Note that we replace the classdict with a regular
# dict before passing it to the superclass, so that we
# don't continue to record member names after the class
# has been created.
result = type.__new__(cls, name, bases, dict(classdict))
result.member_names = classdict.member_names
return result
class MyClass(metaclass=OrderedClass):
# method1 goes in array element 0
def method1(self):
pass
# method2 goes in array element 1
def method2(self):
pass
x = MyClass()
print([name for name in x.member_names if hasattr(getattr(x, name), '__call__')])
Solution 5:
There is probably one of the shortest methods (the class name is C):
for func in filter(lambda x: callable(x), C.__dict__.values()):
pass # here func is the next function, you can execute it here
The filter expression returns all functions of the class C.
OR in one line:
[func() for func in filter(lambda x: callable(x), C.__dict__.values())]
You can order somehow the functions, for example, by lexicographical order of their names by little more complex expression.
Post a Comment for "Is There A Way To Loop Through And Execute All Of The Functions In A Python Class?"