Can we use keyword arguments and curry a function until all arguments are received in any order?
For example I have this code:
def create_folder_transformer(folder):
return lambda predicate: lambda file_transformer: map(file_transformer,
filter(predicate,
os.listdir(folder)))
I can create a folder_transformer
with a specific folder and then mention the`predicate etc. But it has a specific order. However, I don't think it need to be tied to that order.
I would like to achieve something like this instead:
predicate
, I get a partial function that takes folder
and file_transformer
as arguments. Now if I supply folder
, I get a partial function that takes file_transformer
.file_transformer
, I get a partial function that takes predicate
and folder
as arguments. Now if I supply predicate
, I get a partial function that takes folder
.In short, is there an inbuilt partial creator that recursively keeps on generating partial functions until all inputs are obtained; if inputs are satisfied just execute the code. I believe it is called currying in Haskell and it is how functions perform by default.
Use cases where I think it might help:
When I am transforming a specific folder
with n
operations,
creating a partial with folder
will be better.
When I am having a specific predicate like - filter out mp4
files across many folders - a partial with a predicate
like string.endswith(".mp4")
will be better.
I read the partial docs but these partials don't return partials if I haven't filled in some args. But since I have declared it as None
, I can't expect it either. Ideally, I would like my function itself to behave like that without even worrying about using an additional function like partial i.e it should be baked into my function.
def folder_transformer(folder=None, predicate=None, transformer=None):
return map(transformer, filter(predicate, os.listdir(folder)))
file_transformer = partial(folder_transformer, predicate=os.path.isfile)
# This gives me a "map" object, but I want another partial takes "transformer".
current_transformer = file_transformer(folder=folder)
# This works, but my question is can I make my function do this automatically.
current_transformer = partial(file_transformer,folder=folder)
I came with a small script for my personal use.
PS: If anyone knows a library that can do something similar, please let me know.
import inspect
def curry(function):
original_func = function
original_args = inspect.signature(function).parameters
def wrapper(**kwargs):
call = True
current_args = {}
for each in original_args:
if kwargs.get(each):
current_args[each] = kwargs.get(each)
else:
call = False
if call:
original_func(**current_args)
else:
def partial(**nargs):
current_args.update(nargs)
return wrapper(**current_args)
return partial
return wrapper
@curry
def foo(a=None, b=None, c=None):
print(a, b, c)
# first partial
bar_with_a = bar(a=1)
# next partial
bar_with_a_and_b = bar_with_a(b=1)
# next partial
bar_with_a_and_b = bar_with_a_and_b(b=2)
# next partial
bar_with_a_and_b = bar_with_a_and_b(a=2)
# call
bar_with_a_and_b(c=2)