Partially evaluated functions

Nick Perkins nperkins7 at home.com
Wed Jun 20 14:16:21 EDT 2001


"Rainer Deyke" <root at rainerdeyke.com> wrote...

> ...
> My version is superior in that it doesn't use named arguments.  Consider:
>
> def f(self):
>   print self
>
> curry(self = 5) # This will fail with the cookbook version.
>

..Of course, you mean:

curry(f, self=5)

.. which works fine with the cookbook version.
( why wouldn't it? )


> > I notice that that the cookbook version makes a copy of the kwargs
> > dictionary.
> > I suppose this prevents kwargs from being modified after being supplied
to
> > curry.
>
> Tests show that 'kwargs' is always a new object in the current
> implementation, but I suppose that could change in the future.
>


Yes, my tests also show that curry does not need to make a copy of the
kwargs dict.


> > Also the actual call to the function uses the * and ** operators to
> 'expand'
> > the arguments.
>
> My version would have those too if I had been paying attention while I was
> writing it.


I tested your solution, the cookbook version, and Alex's nested_scopes
version.
All three work properly for the kwd args tests that I performed.

Here is the test script:
It tests only kwd args, not positional args.
I omit the output, but in every case the output matched the expected output.


from __future__ import nested_scopes
# (for Alex's version)


# by Rainer Deyke
class curry_RD:
    def __init__(*args, **kwargs):
        self = args[0]
        self.function = args[1]
        self.args = args[2:]
        self.kwargs = kwargs
    def __call__(self,*args, **kwargs):
        kwargs.update(self.kwargs)
        return self.function(*(self.args + args), **kwargs)

# by Scott David Daniels (from cookbook)
class curry_CB:
     def __init__(self, fun, *args, **kwargs):
         self.fun = fun
         self.pending = args[:]
         self.kwargs = kwargs.copy()
     def __call__(self, *args, **kwargs):
         if kwargs and self.kwargs:
             kw = self.kwargs.copy()
             kw.update(kwargs)
         else:
             kw = kwargs or self.kwargs
         return self.fun(*(self.pending + args), **kw)

# by Alex Martelli
# (using nested_scopes)
def curry_AM(func, *args, **kwds):
    def callit(*moreargs, **morekwds):
        morekwds.update(kwds)
        return func(*(moreargs+args), **morekwds)
    return callit


curries = {'Cookbook':curry_CB,'Rainer':curry_RD,  'Alex':curry_AM }

def fn(size='small',color='blue',shape='circle'):
    return '%s %s %s' % (size,color,shape)


for name in curries.keys():
    curry = curries[name]

    print
    print name
    print

    f = curry(fn)
    print 'expect: small blue circle'
    print f()
    print

    print 'expect big red circle'
    f = curry(fn,color='red')
    print f(size='big')
    print

    print 'TEST: nested curries:'
    f = curry(fn, shape='square')
    f2 = curry(f, size = 'big')

    print 'expect big purple square'
    print f2(color='purple')

    print 'expect big blue square'
    print f2()
    print

    kwargs = {'size':'medium','color':'orange','shape':'oval'}
    f = curry(fn,**kwargs)

    print 'expect medium orange oval'
    print f()
    print

    # see if we can change a kwd arg after curry...
    # ( does curry need to copy kwd dict?)

    kwargs['shape']='rectangle'
    print 'expect medium orange oval (not rectangle)'
    print f()
    print









More information about the Python-list mailing list