functools.partial wants to use a positional argument as a keyword argument

So I am trying to understand partial:

import functools

def f(x,y) :
    print x+y

g0 = functools.partial( f, 3 )
g0(1)

4 # Works as expected

In:

g1 = functools.partial( f, y=3 )
g1(1)

4 # Works as expected

In:

g2 = functools.partial( f, x=3 )
g2(1)

TypeError: f() got multiple values for keyword argument 'x'

The TypeError disappears if I use y as a keyword argument:

In:

g2( y=1 )

4

What causes the TypeError?


This has nothing to do with functools.partial, really. You are essentially calling your function like this:

f(1, x=3)

Python first fulfils the positional arguments, and your first argument is x. Then the keyword arguments are applied, and you again supplied x.

functools.partial() has no means to detect that you already supplied the first positional argument as a keyword argument instead. It will not augment your call by replacing the positional argument with a y= keyword argument.

When mixing positional and keyword arguments, you must take care not to use the same argument twice.


To expand on @Martijn-Pieters answer, this is how you can preserve the positional nature of the second parameter. Here, the argument to g2 is passed positionally as y:

def f(x,y) :
    print x+y

g2 = functools.partial( f, *[3] )
g2(1)

That works when we're trying to replace an initial set of the arguments of f. I don't know how to use partial to replace e.g. just the second argument of a 3-parameter function, and allow the first and third to be passed positionally. But you could do that with a lambda expression.