My full question sound this way: How to compose (combine) several function calls with arguments without using partial.
Right now current code below works fine, but I need to call partial every time any additional argument is provided:
from functools import partial
def pipe(data, *funcs):
for func in funcs:
data = func(data)
return data
def mult(data, amount=5, bias=2):
return data*amount + bias
def divide(data, amount, bias=1):
return data/amount + bias
result = pipe(5,
mult,
partial(divide, amount=10)
)
print(result)
# 3.7
But I would like to partial to be called inside of pipe function. So calling should start looking this way:
result = pipe(5,
mult,
divide(amount=10)
)
Here's an implementation that may help you. It's a decorator to use on functions so that you can create partial
function by calling the function itself, rather than partial(func, ...)
:
from functools import partial, wraps
def make_partial(func):
@wraps(func)
def wrapper(*args, **kwargs):
return partial(func, *args, **kwargs)
return wrapper
With any function that you want your behaviour with, decorate it like so:
@make_partial
def divide(data, amount, bias=1):
return data/amount + bias
Now you can call pipe
as you describe as calling divide(amount=10)
now returns a partial too.
result = pipe(5, mult, divide(amount=10))
It would be difficult to make the partial
call within pipe
as you would somehow need to pass in the desired function and its default arguments without calling it. This method tries to eliminate this and keep your existing functions clean.
The only other way I can suggest is that you pass a list of functions, a list of lists of partial args and a list of dicts of keyword arguments. Your function signature would be pipe(data, funcs, args, kwargs)
.
def pipe(data, funcs, args, kwargs):
for func, arg_list, kwarg_list in zip(funcs, args, kwargs):
data = partial(func, *arg_list, **kwarg_list)(data)
return data
To call pipe
, it gets a bit more complicated:
result = pipe(
5,
[mult, divide],
[[], []],
[{}, {'amount': 10}]
)