[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