Currying an arbitrary function in Python is quite annoying (Reference: Try writing currying in Python).
However, you can use callable objects to make it look like you're currying at first glance. Kantannakoto.
When it comes to currying, you'll want to work hard to knead the lambda expression, but with this method you can do the same just by devising the implementation of the Dunder method.
import re
class Curried:
def __init__(self, f, regex=None, *args, **kwargs):
self.__f = f
self.__regex = regex if regex is not None else \
re.compile('{}\\(\\) missing \\d+ required'.format(f.__name__))
self.__args = args if args is not None else ()
self.__kwargs = kwargs if kwargs is not None else {}
def __call__(self, *arg, **kwarg):
cls = type(self)
new_args = self.__args + arg
new_kwargs = dict(**self.__kwargs, **kwarg)
try:
return self.__f(*new_args, **new_kwargs)
except TypeError as e:
if self.__regex.match(e.args[0]):
return cls(self.__f, self.__regex, *new_args, **new_kwargs)
else:
raise e
@property
def __name__(self):
return self.__f.__name__
This Curried
instance takes arguments one by one and continues to create Curried
instances until it fills the arguments of the original function. It's not just a function, it's a callable object like a function.
Use it this way.
def add(x, y):
return x + y
def add3(x, y, z):
return x + y + z
print(Curried(add)(2)(3))
print(Curried(add3)(2)(3)(4))
5
9
At first glance it looks like you're calling a curried function, right?
It can also be used for object methods.
class Foo(object):
def __init__(self, seed=1):
self.seed = seed
def add(self, x, y):
return self.seed * (x + y)
def multiply(self, x, y):
return self.seed * x * y
f = Foo(3)
print(Curried(f.add)(2)(3))
print(Curried(f.multiply)(2)(3))
15
18
You can also reuse currying functions (which seems to be persistent, but this one isn't really a function) that you couldn't do in the reference article.
add2 = Curried(add)(2)
print(add2(3))
print(add2(4))
5
6
Recommended Posts