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

Python 是否可以部分应用不带关键字参数的函数的第二个参数?,python,arguments,partial-application,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] 但是如何将xs提升到2的幂呢 获取[1,4,9,16,25,49,64] list(map(partial(pow,y=2),xs)) TypeError: pow() takes no keyword

以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]
但是如何将xs提升到2的幂呢

获取
[1,4,9,16,25,49,64]

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

TypeError: pow() takes no keyword arguments

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

一种方法是:

def testfunc1(xs):
    from functools import partial
    def mypow(x,y): return x ** y
    return list(map(partial(mypow,y=2),xs))
但这涉及到重新定义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]
如果不需要使用partial,那么简单的lambda就可以了

def testfunc2(xs):
    return list(map(lambda x: pow(x,2), xs))
绘制2号战俘地图的具体方法是

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

但是这些都不能完全解决与关键字参数相关的部分应用的问题

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

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)

免责声明:我还没有用关键字参数测试过它,所以它可能会因为它们而爆炸。另外,我不确定这是否是
@wrapps
应该使用的,但它似乎是正确的。

您可以使用闭包

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)
不 根据,不能这样做(强调我自己):

partial.args

将在位置参数前面加上的最左边的位置参数


您可以始终“修复”
pow
以获得关键字参数:

_pow = pow
pow = lambda x, y: _pow(x, y)

我想我应该用这个简单的一行:

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

我还提出了一个比有用的更有趣的解决方案。这是一个漂亮的语法糖,得益于Python3中
..
字面意思是
省略。它是
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

所以原始问题的解决方案是使用这个版本的partial
列表(map(partial(pow,…,2),xs))

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

partial(lambda p, x: pow(x, p), 2)

如前所述,如果要
partial
的函数不接受关键字参数,则这是一个限制

如果您不介意使用外部库1,您可以使用具有支持占位符的分部的库1:

>>> from iteration_utilities import partial
>>> square = partial(pow, partial._, 2)  # the partial._ attribute represents a placeholder
>>> list(map(square, xs))
[1, 4, 9, 16, 25, 36, 49, 64]


1免责声明:我是库的作者(如果您感兴趣,可以找到安装说明)。

您可以使用
lambda
,它比
functools.partial()更灵活:

更一般地说:

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
lambda的一个缺点是某些库无法对其进行序列化。

非常通用的lambda包含一个
r部分
函数,该函数正好解决了这个问题

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]
它只是引擎盖下的一个lambda:

def rpartial(func, *args):
    """Partially applies last arguments."""
    return lambda *a: func(*(a + args))

如果不能使用lambda函数,还可以编写一个简单的包装函数来重新排序参数

def _pow(y, x):
    return pow(x, y)
然后打电话

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

>>> [1, 4, 9, 16, 25, 36, 49, 64]

即使这个问题已经得到了回答,您也可以通过以下配方获得您想要的结果:

从itertools导入重复
xs=list(范围(1,9))#[1,2,3,4,5,6,7,8]
xs_pow_2=列表(映射(pow,xs,repeat(2))#[1,4,9,16,25,36,49,64]


希望这对某人有所帮助。

这应该添加到问题中,而不是作为答案发布。昨天有人建议我添加我的尝试作为答案,而不是问题。这不是一个双赢的局面!我想这里没问题。你应该更多地用“这里有一种方法”来表达,而不是作为问题的补充。在某种程度上,假装你是另一个人在回答。也许看看@Eric,只是读一下。我认为这个答案是正确的。我将把它调整为bitMajor+1。我很想选择这个答案,但我想我考虑的更多的是内置的
functools.partial
。但这肯定是被拯救了。我喜欢:)不错,因为某种原因我从不重复。当我在3.X上时,它只是
list(map(pow,[1,2,3],itertools.repeat(2))
nice,我不知道它们在python3中改变了
map
。有趣的是,它以一种有点可怕的方式非常聪明:P(而且,你一开始就不应该传递省略号,所以这不是一个很大的缺点。除非你计算在内)“使用省略号表示不应该使用的内容”是一个缺点。)在学习了一些函数编程之后,对我来说,这看起来像是一种奇怪的函数插入方式python@kosii这正是它的特点。令人印象深刻的是,Python足够灵活,可以简化许多功能模式“,我们都知道他们的想法是从哪里来的:)@beoliver:事实上,到目前为止,仅位置参数已被形式化为一种功能,因此我永远不会期望在这里使用lambda时修复
pow
,您不再需要
functools.partial()
。这是干什么的?参数一点也没有改变:我会预料到x,y->y的顺序会发生逆转,x根据我的评论:
lambda x,y
\u pow(x,y)
中的一个或另一个是否应该反转
x,y
从第二个参数开始的partial的另一个用法对于方法是partial的省略您可以使用的方法的自论证:
def meth(cls,self,…)
然后
partial(meth,cls)
您对某些库的意思是什么?我认为没有库能够序列化它们。我经常使用ruamel.yaml,它可以很好地序列化lambdas。好的,我在考虑内置模块。谢谢你的澄清:)不完全是。第二个参数不一定是最后一个参数。我只是发现该方法在定义属性(直接使用property()函数,而不是作为装饰器)时很有用,我需要将第二个参数默认为_usetItem__;()调用。在这一点上,为什么不使用它?为什么f=lambda p,x=2:pow(x,p)。或偶数f=lambda p:pow(2,p)