Can one partially apply the second argument of a f

2019-01-08 18:36发布

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.

10条回答
SAY GOODBYE
2楼-- · 2019-01-08 18:49

Why not just create a quick lambda function which reorders the args and partial that

partial(lambda p, x: pow(x, p), 2)
查看更多
再贱就再见
3楼-- · 2019-01-08 18:49

The very versatile funcy includes an rpartial function that exactly addresses this problem.

xs = [1,2,3,4,5,6,7,8]
from funcy import rpartial
list(map(rpartial(pow, 2), xs))
# [1, 4, 9, 16, 25, 36, 49, 64]

It's just a lambda under the hood:

def rpartial(func, *args):
    """Partially applies last arguments."""
    return lambda *a: func(*(a + args))
查看更多
Melony?
4楼-- · 2019-01-08 18:53

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)
查看更多
时光不老,我们不散
5楼-- · 2019-01-08 18:59

You can do this with lambda, which is more flexible than functools.partial():

pow_two = lambda base: pow(base, 2)
print(pow_two(3))  # 9

More generally:

def bind_skip_first(func, *args, **kwargs):
  return lambda first: func(first, *args, **kwargs)

pow_two = bind_skip_first(pow, 2)
print(pow_two(3))  # 9

One down-side of lambda is that some libraries are not able to serialize it.

查看更多
唯我独甜
6楼-- · 2019-01-08 19:00

One way of doing it would be:

def testfunc1(xs):
    from functools import partial
    def mypow(x,y): return x ** y
    return list(map(partial(mypow,y=2),xs))

but this involves re-defining the pow function.

if the use of partial was not 'needed' then a simple lambda would do the trick

def testfunc2(xs):
    return list(map(lambda x: pow(x,2), xs))

And a specific way to map the pow of 2 would be

def testfunc5(xs):
    from operator import mul
    return list(map(mul,xs,xs))

but none of these fully address the problem directly of partial applicaton in relation to keyword arguments

查看更多
冷血范
7楼-- · 2019-01-08 19:00

If you can't use lambda functions, you can also write a simple wrapper function that reorders the arguments.

def _pow(y, x):
    return pow(x, y)

and then call

list(map(partial(_pow,2),xs))

>>> [1, 4, 9, 16, 25, 36, 49, 64]
查看更多
登录 后发表回答