Created
August 1, 2014 10:51
-
-
Save JulienPalard/021f1c7332507d6a494b to your computer and use it in GitHub Desktop.
KISS Python curry
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
def curry(func): | |
""" | |
Decorator to curry a function, typical usage: | |
>>> @curry | |
... def foo(a, b, c): | |
... return a + b + c | |
The function still work normally: | |
>>> foo(1, 2, 3) | |
6 | |
And in various curried forms: | |
>>> foo(1)(2, 3) | |
6 | |
>>> foo(1)(2)(3) | |
6 | |
This also work with named arguments: | |
>>> foo(a=1)(b=2)(c=3) | |
6 | |
>>> foo(b=1)(c=2)(a=3) | |
6 | |
>>> foo(a=1, b=2)(c=3) | |
6 | |
>>> foo(a=1)(b=2, c=3) | |
6 | |
And you may also change your mind on named arguments, | |
But I don't know why you may want to do that: | |
>>> foo(a=1, b=0)(b=2, c=3) | |
6 | |
Finally, if you give more parameters than expected, the exception | |
is the expected one, not some garbage produced by the currying | |
mechanism: | |
>>> foo(1, 2)(3, 4) | |
Traceback (most recent call last): | |
... | |
TypeError: foo() takes exactly 3 arguments (4 given) | |
""" | |
def curried(*args, **kwargs): | |
if len(args) + len(kwargs) >= func.__code__.co_argcount: | |
return func(*args, **kwargs) | |
return (lambda *args2, **kwargs2: | |
curried(*(args + args2), **dict(kwargs, **kwargs2))) | |
return curried | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fantastic! Thanks!
You may use
functools.wraps
to make the intermediate curried functions look like the original function.Now instead of showing
<function __main__.curry.<locals>.curried.<locals>.<lambda>>
forfoo(1)
, we have the expected representation of the function. This can make debugging easier.