Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 454
usual me Avatar asked Jul 15 '14 10:07

usual me


People also ask

Can positional arguments be used with keyword arguments?

Keyword arguments are passed to functions after any required positional arguments. But the order of one keyword argument compared to another keyword argument does not matter.

What does partial do in Functools?

You can create partial functions in python by using the partial function from the functools library. Partial functions allow one to derive a function with x parameters to a function with fewer parameters and fixed values set for the more limited function. This code will return 8.

Can positional arguments be used with keyword arguments Python?

Keyword arguments aren't just useful for functions that accept any number of positional arguments (like print ). You can pass keyword arguments to just about any function in Python. We're passing in one positional argument and one keyword argument. That start=1 works with sum because start is the name of that argument.

What is positional and keyword arguments?

A positional argument means its position matters in a function call. A keyword argument is a function argument with a name label. Passing arguments as keyword arguments means order does not matter. Thanks for reading.


2 Answers

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.

like image 119
Martijn Pieters Avatar answered Sep 19 '22 12:09

Martijn Pieters


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.

like image 44
nealmcb Avatar answered Sep 19 '22 12:09

nealmcb