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 May 19, 2022.