Reputation: 3923
I have a code like this. In my original code I would like to call two or more methods when a button is clicked.
class MyApp(object):
@staticmethod
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def __init__(self):
MyApp.combine_funcs(self.my_first_func, self.my_second_func)
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
my_app = MyApp()
When I run this nothing is printed. Why?
Upvotes: 0
Views: 4128
Reputation: 149085
A method is not much more than a member of a class that happens to be a function. The magic is just that when it is called on an object (a.func(x...)
) the object is automatically prepended in the argument list resulting in the actual call A.func(a, x...)
.
What you want can be obtained that way:
class MyApp(object):
# prepend with _ to "hide" the symbol
def _combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
# actually declares combined as a method of MyClass
combined = _combine_funcs(my_first_func, my_second_func)
Usage:
>>> a = MyApp()
>>> a.combined()
First
Second
But a much cleaner way would be to use a decorator for that in Python 3:
import inspect
def combine_funcs(*funcs):
def outer(f):
def combined_func(*args, **kwargs): # combine a bunch of functions
for f in funcs:
x = f(*args, *kwargs)
return x # returns return value of last one
combined_func.__doc__ = f.__doc__ # copy docstring and signature
combined_func.__signature__ = inspect.signature(f)
return combined_func
return outer
class MyApp(object):
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
@combine_funcs(my_first_func, my_second_func)
def combined(self):
"""Combined function"""
pass
The decorator will replace the body but will keep the docstring and the signature of the original function (in Python 3). You can then use it normally:
>>> a = MyApp()
>>> a.combined()
First
Second
>>> help(a.combined)
Help on method combined_func in module __main__:
combined_func() method of __main__.MyApp instance
Combined function
>>> help(MyApp.combined)
Help on function combined_func in module __main__:
combined_func(self)
Combined function
Upvotes: 2
Reputation: 106
You're calling combine_funcs
, but the function within that, combined_func
, is not being called.
Is there a reason not to simplify to:
class MyApp(object):
@staticmethod
def combined_func(*args, **kwargs):
for f in args:
f()
def __init__(self):
MyApp.combined_func(self.my_first_func, self.my_second_func)
def my_first_func(self):
print("First")
def my_second_func(self):
print("Second")
my_app = MyApp()
Upvotes: 0