[Python-ideas] @partials = decorators
Ron Adam
ron3200 at gmail.com
Mon Feb 10 00:21:08 CET 2014
More information about the Python-ideas mailing list
Mon Feb 10 00:21:08 CET 2014
- Previous message: [Python-ideas] @partials = decorators
- Next message: [Python-ideas] @partials = decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 02/08/2014 04:46 PM, Ian Cordasco wrote: > I experimented with something similar over at > https://github.com/sigmavirus24/curryer but never released it. It's > fairly well tested but I'm not sure I'd use it for anything other > than a toy. Thanks I take a look, probably later this week, and see what is different. Today I made a nicer version. This fits both uses as decorator helpers and as a way to capture arguments for nested functions.What it's does is factor out nesting used to capture the arguments. And has some useful properties to help it work in more situations than the functools partial function. It also expresses lambda expressions surprisingly well! ;-) @P def I(x): """ I := λx.x (Identity) """ return x @P def K(x, y): """ K := λx.λy.x """ return x @P def S(x, y, z): """ S := λx.λy.λz.x z (y z) """ return x(z)(y(z)) # Use "_" as the lambda symbol. _ = P # Allows _(S, K, K, Z) in place of S(K)(K)(Z) or S(K, K, Z) assert _(I, 'A'), 'A' assert _(K, 'A', 'B'), 'B' assert _(S, K, K, 'C'), 'C' # Yes, This really works! :-) When I get back from a short 3 day trip, I'm going to test how it works in the library by replacing occurrences of "\n at ..." with "\n at P(...)" and see what breaks. Should be interesting. I expect it to get hung up on optional args and keywords in places. But possibly not, as they will be included at the same time the partial is complete in most, if not all cases. One thing that bother me is that, catching TypeError is way to general. It would be very nice if "wrong number of args" raised a subclass of TypeError so we can test for just that type of error. Cheers, Ron (Tests not included to keep it short.) ------------------------------------------------------ """ ### 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) # TODO: A partial depth control function.
- Previous message: [Python-ideas] @partials = decorators
- Next message: [Python-ideas] @partials = decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-ideas mailing list