Python 如何为functool partial()指定参数位置

Python 如何为functool partial()指定参数位置,python,lambda,decorator,currying,Python,Lambda,Decorator,Currying,根据手册,functoolspartial() 指定希望评估的参数位置的最佳方法是什么 编辑 注意:根据注释,要部分计算的函数可能包含命名和未命名的参数(这些函数应该是完全任意的,并且可能是预先存在的) 结束编辑 例如,考虑: def f(x,y,z): return x + 2*y + 3*z 然后,使用 from functools import partial 两者 及 给32 但是如果要计算,比如说第三个参数z,或者第一个和第三个参数x,和z 是否有一种方便的方法将位置信息

根据手册,
functools
partial()

指定希望评估的参数位置的最佳方法是什么

编辑

注意:根据注释,要部分计算的函数可能包含命名和未命名的参数(这些函数应该是完全任意的,并且可能是预先存在的)

结束编辑

例如,考虑:

def f(x,y,z):
    return x + 2*y + 3*z 
然后,使用

from functools import partial
两者

给32

但是如果要计算,比如说第三个参数
z
,或者第一个和第三个参数
x
,和
z

是否有一种方便的方法将位置信息传递给
partial
,方法是使用
装饰器
dict
,其键为所需的arg位置,相应的值为arg值?例如,通过
x
z
这样的位置:

partial_dict(f,{0:4,2:6})(5)
def partial_positionals(func, positionals, **keywords):
    def wrapper(*args, **kwargs):
        arg = iter(args)
        return func(*(positionals[i] if i in positionals else next(arg)
            for i in range(len(args) + len(positionals))), **{**keywords, **kwargs})
    return wrapper

只需使用关键字参数。使用上述
f
的定义

>>> g = partial(f, z=10)
>>> g(2, 4)
40
>>> h = partial(f, y=4, z=10)
>>> h(2)
40
请注意,一旦对给定参数使用关键字参数,就必须对所有剩余参数使用关键字参数。例如,以下内容无效:

>>> j = partial(f, x=2, z=10)
>>> j(4)
TypeError: f() got multiple values for argument 'x'
但继续使用关键字参数是:

>>> j = partial(f, x=2, z=10)
>>> j(y=4)
40
使用
functools.partial
时,存储
*args
**kwargs
的值,以便以后插值。稍后调用“partially applied”函数时,
functools.partial
的实现有效地将先前提供的
*args
**kwargs
分别添加到前端和后端的参数列表中,就好像您自己插入了这些参数解包一样。也就是说,打电话

h = partial(1, z=10)
f(4)
大致相当于写作

args = [1]
kwargs = {'z': 10}
f(*args, 4, **kwargs)

因此,如何向
functools.partial
提供参数的语义与需要如何将参数存储在上面的
args
kwargs
变量中相同,以便对
f
的最终调用是合理的。有关更多信息,请查看
functools.partial的psedoo实现。在

否中给出的
partial
不是为在非顺序位置冻结位置参数而设计的

要实现问题中概述的所需行为,您必须提出自己的包装函数,如下所示:

partial_dict(f,{0:4,2:6})(5)
def partial_positionals(func, positionals, **keywords):
    def wrapper(*args, **kwargs):
        arg = iter(args)
        return func(*(positionals[i] if i in positionals else next(arg)
            for i in range(len(args) + len(positionals))), **{**keywords, **kwargs})
    return wrapper
以便:

def f(x, y, z):
    return x + 2 * y + 3 * z

print(partial_positionals(f, {0: 4, 2: 6})(5))
def f(x, y, z):
    return x + 2 * y + 3 * z

print(partial_positionals(f, 4, SKIP, 6)(5))
产出:

32
32

为了便于使用,您可以专门创建一个新对象来指定一个位置参数,当使用
partial
顺序列出要冻结的位置参数值时,将跳过该位置参数:

SKIP = object()

def partial_positionals(func, *positionals, **keywords):
    def wrapper(*args, **kwargs):
        arg = iter(args)
        return func(*(*(next(arg) if i is SKIP else i for i in positionals), *arg),
            **{**keywords, **kwargs})
    return wrapper
以便:

def f(x, y, z):
    return x + 2 * y + 3 * z

print(partial_positionals(f, {0: 4, 2: 6})(5))
def f(x, y, z):
    return x + 2 * y + 3 * z

print(partial_positionals(f, 4, SKIP, 6)(5))
产出:

32
32

听起来像个XY问题。使用关键字,在这种情况下不使用位置。第三个参数很简单:只需使用
partial(f,z=4)
并在调用时传递x,y参数作为位置参数。@Jean-Françoisfare,不,这些参数没有命名-看看示例中
f
的定义,不能假设它们被命名为函数,因为函数可能是预先存在的。将编辑Q以澄清。@alancalvitti你能澄清你所说的“未命名的论点”是什么意思吗?你是说C API定义的函数没有参数名、参数或变量
*args
样式参数吗?除了这些特殊情况外,Python中所有常规定义的函数都可以使用关键字参数代替位置参数来调用。@Brian,没有参数名称,就像上面示例中的
f
。我认为它不能很好地处理
*arg
样式参数,但它也应该处理命名参数。@alancalvitti我看到了三个参数名,
x
y
,和
z
…我正在寻找一个通用的解决方案,无论是命名的还是未命名的参数-请参阅我对Jean Francois的评论以及随后在我的问题中的澄清。@alancalvitti我的回答的后半部分涉及一般情况。传递给
functools.partial
的所有内容都将表现为您以上面提供的样式手动存储和解包参数。如果您不能使用关键字参数(由于我在上面对您的问题的评论中提到的三个原因之一),您可能需要定义一个可以部分计算的包装函数。我已经更新了答案,允许为自定义
部分
函数指定默认关键字参数,正如你的评论所建议的。谢谢,我已经接受了。但我也想问一下,您是否认为有更方便的语法方法来指定所持有的参数,即,不计算参数。例如,在另一种语言(Mathematica)中,您可以像这样使用一个项目符号(选项8)
f(x,•,z)
将该函数转换为部分计算的
f(x,z)
。我认为这在python中是不可行的,但也许有类似的方法?不客气。我不认为有任何内置的东西接近Python中的这种用法。您想要实现的功能通常是通过为
partial
函数指定关键字参数来实现的,而且可以说是更加pythonical的。在Python中,位置参数是按顺序指定的。我添加了一个新的答案,以根据Mathematica风格的部分参数规范定制解决方案。Re“您想要的是……通过指定关键字参数来实现更pythonical的功能”。不,那不是我的本意。我想我需要重新措辞这个问题。我正在为任何函数寻找一个通用的部分求值解决方案,包括预先存在的函数,它们可能有也可能没有关键字arg,即使有,您通常也希望保留一个非关键字arg。