circuitpython_1024px-Pointed_Gourd_Curry_-_Kolkata_2011-09-20_5428.jpg
Bengali gourd curry by wikipedia user Kolkata CC BY 3.0

When thinking about a more general way to partially apply a functions, it would seem to be nice to partially apply to any number of argument, and to handle keyword arguments. As an exercise, we'll build it up step by step.

Let's start by considering the general form of the partial application function. We'll need to provide the function to be partially applied and the arguments to which it should be partially applied. We'll start with positional arguments.

def partial(func, *args):
    pass

The next step is to create the function to capture the partial application:

def partial(func, *args):
    def newfunc(*fargs):
        pass

    return newfunc

newfunc has to take the arguments that are passed to it and combine them with those supplied earlier (to the partial function), then call the original function with the resulting arguments:

def newfunc(*fargs):
    return func(*(args + fargs))

It can simply concatenate the positional arguments (keeping the order correct) since they are in lists.

The partial function is now:

def partial(func, *args):
    def newfunc(*fargs):
        return func(*(args + fargs))
    return newfunc

Now we can say:

>>> inc = partial(add, 1)
>>> inc(2)
3

With Keywords

Now we can add keyword arguments. We can make a simple function to build strings:

>>> def wrap(s, prefix='', suffix=''):
... return prefix + s + suffix
...
>>> wrap('hello')
'hello'
>>> wrap('hello', suffix=' world')
'hello world'
>>> wrap('hello', suffix=' world', prefix='>>> ')
'>>> hello world'

We can use partial application to take wrap and make a greeter function:

>>> greet = partial(wrap, prefix='Hello, ')
>>> greet('Dave')
'Hello, Dave'

>>> greet('Phil', suffix='!')
'Hello, Phil!'

To expand partial to extend partial application to keyword arguments, we need to add them to the functions, and combine them for the fully applied call. Since they are passed in dictionaries, we can't simply concatenate the way we did with the positional arguments; we need to merge the dictionaries using update. Our new partial function is now:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    return newfunc

This guide was first published on Mar 27, 2019. It was last updated on Mar 27, 2019.

This page (More Complex Partial Application) was last updated on Mar 23, 2019.

Text editor powered by tinymce.