Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can one partially apply the second argument of a function that takes no keyword arguments?

Take for example the python built in pow() function.

xs = [1,2,3,4,5,6,7,8]  from functools import partial  list(map(partial(pow,2),xs))  >>> [2, 4, 8, 16, 32, 128, 256] 

but how would I raise the xs to the power of 2?

to get [1, 4, 9, 16, 25, 49, 64]

list(map(partial(pow,y=2),xs))  TypeError: pow() takes no keyword arguments 

I know list comprehensions would be easier.

like image 457
beoliver Avatar asked Jun 23 '12 22:06

beoliver


People also ask

Can non-keyword arguments be passed after keyword arguments?

Yes, Python enforces an order on arguments: all non-keyword arguments must go first, followed by any keyword arguments.

Can you pass unnamed arguments into a function in Python?

Yes. You can use *args as a non-keyword argument.

What are non-keyword arguments?

1. Non-keyword Variable Arguments (Tuple) When a function is invoked, all formal (required and default) arguments are assigned to their corresponding local variables as given in the function declaration. The remaining non-keyword variable arguments are inserted in order into a tuple for access.

How many arguments Help function can take?

Except for functions with variable-length argument lists, the number of arguments in a function call must be the same as the number of parameters in the function definition. This number can be zero. The maximum number of arguments (and corresponding parameters) is 253 for a single function.


2 Answers

No

According to the documentation, partial cannot do this (emphasis my own):

partial.args

The leftmost positional arguments that will be prepended to the positional arguments


You could always just "fix" pow to have keyword args:

_pow = pow pow = lambda x, y: _pow(x, y) 
like image 200
Eric Avatar answered Sep 20 '22 12:09

Eric


I think I'd just use this simple one-liner:

import itertools print list(itertools.imap(pow, [1, 2, 3], itertools.repeat(2))) 

Update:

I also came up with a funnier than useful solution. It's a beautiful syntactic sugar, profiting from the fact that the ... literal means Ellipsis in Python3. It's a modified version of partial, allowing to omit some positional arguments between the leftmost and rightmost ones. The only drawback is that you can't pass anymore Ellipsis as argument.

import itertools def partial(func, *args, **keywords):     def newfunc(*fargs, **fkeywords):         newkeywords = keywords.copy()         newkeywords.update(fkeywords)         return func(*(newfunc.leftmost_args + fargs + newfunc.rightmost_args), **newkeywords)     newfunc.func = func     args = iter(args)     newfunc.leftmost_args = tuple(itertools.takewhile(lambda v: v != Ellipsis, args))     newfunc.rightmost_args = tuple(args)     newfunc.keywords = keywords     return newfunc  >>> print partial(pow, ..., 2, 3)(5) # (5^2)%3 1 >>> print partial(pow, 2, ..., 3)(5) # (2^5)%3 2 >>> print partial(pow, 2, 3, ...)(5) # (2^3)%5 3 >>> print partial(pow, 2, 3)(5) # (2^3)%5 3 

So the the solution for the original question would be with this version of partial list(map(partial(pow, ..., 2),xs))

like image 41
kosii Avatar answered Sep 20 '22 12:09

kosii