Adrian Holovaty wrote: > On 9/6/06, Martin <[EMAIL PROTECTED]> wrote: >> def curry(fct, *args, **kwargs): >> def _curried(*moreargs, **morekwargs): >> return fct (* (args+moreargs), **dict(kwargs, ** morekwargs)) >> return _curried >> >> It's just a performance issue (saving a few list operations) andbecause >> I have to use CGI I care about performance at bit more than others ... > > Thanks for the great catch and fix, Martin! I've checked in your > change in changeset 3733. Please do let us know if you find any other > places we could optimize. > > Adrian > Martin's version is indeed faster, but has a 'gotcha' in that it precludes passing a keyword arguments named 'fct' to a curried function...
>>> def curry1(*args, **kwargs): ... def _curried(*moreargs, **morekwargs): ... return args[0](*(args[1:]+moreargs), **dict(kwargs.items() + ... morekwargs.items())) ... return _curried ... ... >>> def curry2(fct, *args, **kwargs): ... def _curried(*moreargs, **morekwargs): ... return fct (* (args+moreargs), **dict(kwargs, ** morekwargs)) ... return _curried ... Check the speed up... >>> def adder(a,b,c,d): ... return a+b+c+d ... >>> adder_cur1 = curry1(adder, 1, 2) >>> adder_cur2 = curry2(adder, 1, 2) >>> shell.timefunc(adder_cur1, 3, 4) '_curried(...) 37276 iterations, 13.41usec per call' >>> shell.timefunc(adder_cur2, 3, 4) '_curried(...) 54986 iterations, 9.09usec per call' which is about 30% faster in this case However... >>> def adder2(a,b,c,d, fct=sum): ... return fct([a,b,c,d]) ... >>> import sys >>> p1 = curry1(1,2, fct="".join) >>> p2 = curry2(1,2, fct="".join) ... Traceback (most recent call last): File "<input>", line 1, in ? TypeError: curry2() got multiple values for keyword argument 'fct' >>> Oops. Better to rename fct to something less likely to clash, such as _curried_fct If you're really hunting for speed, there is a significant boost available in the common special case of a python function curried with one positional argument. In this case, you can [ab]use the method binding machinery, e.g.: def curry3(_curried_fct, *args, **kwargs): if len(args) == 1: # Special case where we try to abuse the descriptor try: return _curried_fct.__get__(args[0]) except AttributeError: # built-ins fail - handle them in the normal way pass def _curried(*moreargs, **morekwargs): return _curried_fct (*(args+moreargs), **dict(kwargs, ** morekwargs)) return _curried This is about twice as fast as curry2 for the case of a python function curried with one argument. It also offers better introspection than either curry1 or curry2, since the original signature is preserved. It's a bigger change than the curry2 though, since it changes the type of the curry from function to bound method. Michael --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-developers -~----------~----~----~----~------~----~------~--~---