可以部分应用不带关键字参数的函数的第二个参数吗?

beo*_*ver 38 python arguments partial-application

以python内置pow()函数为例.

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]
Run Code Online (Sandbox Code Playgroud)

但是我如何将xs提高到2的幂?

要得到 [1, 4, 9, 16, 25, 49, 64]

list(map(partial(pow,y=2),xs))

TypeError: pow() takes no keyword arguments
Run Code Online (Sandbox Code Playgroud)

我知道列表理解会更容易.

Eri*_*ric 36

没有

根据文档,不能这样做(强调我自己):partial

partial.args

最左边的将被前置到位置参数位置参数


您可以随时"修复" pow以获得关键字参数:

_pow = pow
pow = lambda x, y: _pow(x, y)
Run Code Online (Sandbox Code Playgroud)

  • 在这里使用lambda时,你不再需要`functools.partial()`了. (3认同)

kos*_*sii 13

我想我只是使用这个简单的单线程:

import itertools
print list(itertools.imap(pow, [1, 2, 3], itertools.repeat(2)))
Run Code Online (Sandbox Code Playgroud)

更新:

我还提出了一个比有用的解决方案更有趣的方法.它是一个美丽的语法糖,从Python3 中的...字面意思Ellipsis中获益.它是一个修改版本partial,允许省略最左边和最右边的一些位置参数.唯一的缺点是你不能再传递省略号作为参数.

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
Run Code Online (Sandbox Code Playgroud)

所以原始问题的解决方案将是这个版本的部分 list(map(partial(pow, ..., 2),xs))

  • 很好,出于某种原因,我从不使用重复。当我在 3.X 上时,它只是 `list(map(pow, [1, 2, 3], itertools.repeat(2)))` (2认同)
  • 在学习了一些函数式编程之后,对我而言,它看起来像是python中一种奇怪的函数调用方式 (2认同)

nro*_*rob 11

为什么不创建一个快速的lambda函数来重新排序args和partial

partial(lambda p, x: pow(x, p), 2)
Run Code Online (Sandbox Code Playgroud)

  • 既然如此,何必偏袒呢?为什么不是 f = lambda p, x=2: pow(x, p)。甚至 f = lambda p: pow(2, p) (3认同)

mil*_*ose 6

您可以为此创建一个辅助函数:

from functools import wraps
def foo(a, b, c, d, e):
    print('foo(a={}, b={}, c={}, d={}, e={})'.format(a, b, c, d, e))

def partial_at(func, index, value):
    @wraps(func)
    def result(*rest, **kwargs):
        args = []
        args.extend(rest[:index])
        args.append(value)
        args.extend(rest[index:])
        return func(*args, **kwargs)
    return result

if __name__ == '__main__':
    bar = partial_at(foo, 2, 'C')
    bar('A', 'B', 'D', 'E') 
    # Prints: foo(a=A, b=B, c=C, d=D, e=E)
Run Code Online (Sandbox Code Playgroud)

免责声明:我没有使用关键字参数对此进行测试,因此它可能因某种原因而爆炸.此外,我不确定这是否@wraps应该用于,但它似乎是正确的.


iru*_*var 5

你可以使用一个闭包

xs = [1,2,3,4,5,6,7,8]

def closure(method, param):
  def t(x):
    return method(x, param)
  return t

f = closure(pow, 2)
f(10)
f = closure(pow, 3)
f(10)
Run Code Online (Sandbox Code Playgroud)