functools.partial doesn't work without using named parameter

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Mar 25 03:04:47 EDT 2011


On Thu, 24 Mar 2011 23:30:29 -0700, Paddy wrote:

> Hi, I just found the following oddity where for function fsf1 I am
> forced to use a named parameter for correct evaluation and was wondering
> why it doesn't work, yet the example from the docs of wrapping int to
> create basetwo doesn't need this? The example:
> 
>>>> from functools import partial
>>>> basetwo = partial(int, base=2)
>>>> basetwo('10010')
> 18

When you call basetwo, it gets passed one positional argument and one 
keyword argument. The positional arguments are bound from left to right, 
as is normal in Python:

int expects to be called like int(a, [base=]b)
int gets passed two arguments: int('10010', base=2)

so all is well. The string '10010' gets bound to the first argument, and 
the keyword argument 2 gets bound to the second.



>>>> def fs(f, s): return [f(value) for value in s]
> 
>>>> def f1(value): return value * 2
> 
>>>> s = [0, 1, 2, 3]
>>>> fs(f1, s)
> [0, 2, 4, 6]

All these f's and s's give me a headache. It's easier to discuss if you 
give them distinctive names: spam, ham, eggs are conventions in Python, 
foo, bar, baz in some other languages.



>>>> fsf1 = partial(fs, f=f1)
>>>> fsf1(s)
> Traceback (most recent call last):
>   File "<pyshell#24>", line 1, in <module>
>     fsf1(s)
> TypeError: fs() got multiple values for keyword argument 'f'


fs expects to be called like fs(f, s). It gets called with one positional 
argument, [0,1,2,3], which gets bound to the left-most parameter f, and 
one keyword argument, f1, which *also* gets bound to the parameter f 
(only by name this time, instead of by position).


>>>> # BUT
>>>> fsf1(s=s)
> [0, 2, 4, 6]

Now, because you're calling fsf1 with keyword argument, fs gets called:

fs(f=f1, s=[0,1,2,3])



-- 
Steven



More information about the Python-list mailing list