[Python-ideas] @partials = decorators
Ron Adam
ron3200 at gmail.com
Mon Feb 10 02:11:12 CET 2014
That got de-indented.... so here it is again... :-/
"""
### NOTE: NOT FULLY TESTED!!! Especially with keywords.
A PARTIAL PROTOCOL:
Takes partial number of args and applies them to
a callable. Calls the callable when all it's
functions are present, else returns an updated
partial object.
THE RULES:
* A partial is equivalent to the sum of it's partials.
P(f, a, b, c) == P(f)(a)(b)(c)
* A complete partial is equivalent to the function f
When all the parts are provided.
P(f, a, b, c) == f(a, b, c)
* If f takes no arguments. (same rule)
P(f) == f()
* And empty partial evaluates to a partial.
P() == P
* If f requires at least one (not provided) argument.
P(f)() == P(f)
P()(f) == P(f)
ERROR CASES:
P(1)() # P(1) --> 1, 1 is not a callable.
(* probably more)
CONTROLS:
It's possible to add controls for both the number of args,
and number of Partial calls.
Author: Ronald Adam (ron3200 at gmail.com)
"""
class CollectMore:
""" Collect more args and keywords. """
def __init__(self, f, *args, **kwds):
self.f = f
self.args = list(args)
self.kwds = kwds
def __call__(self, *args, **kwds):
args = self.args + list(args)
self.kwds.update(kwds)
return self.f(*args, **self.kwds)
def P(*args, **kwds):
""" P - Partial function """
if len(args) == len(kwds) == 0:
return P
if len(args) > 0:
f = args[0]
if callable(f):
a = args[1:]
try:
# No required args needed.
# or all required args present.
return f(*a, **kwds)
except TypeError:
# Better way to do this?
pass
elif len(args) == 1 and len(kwds) == 0:
return f
return CollectMore(P, *args, **kwds)
# The implementation above also makes the functions that
# use partial decorators become partials too. To avoid
# that you can use an N-partial (vs impartial) partial
# decorator.
@P
def NP(n, f, *args, **kwds):
""" NP - N-Partial function
Example:
# Pass only 3 arguments for foo.
@NP(3)
def foo(*args):
return args
"""
print("NP", n, f, *args, **kwds)
if len(args) == 0:
raise TypeError # Ready for rest, Partial catches this.
elif len(args) < n:
raise ValueError("%s is partial to %s values" % (f.__name__, n))
elif len(args) > n:
raise ValueError("%s is partial to %s values" % (f.__name__, n))
else:
return f(*args, **kwds)
More information about the Python-ideas
mailing list