如何为 functool partial() 指定参数位置
How to specify arg position for functool partial()
根据手册,functools
partial()
是 'used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature.'
指定要计算的参数位置的最佳方法是什么?
编辑
请注意,根据评论,要部分评估的函数可能包含命名和未命名的参数(这些函数应该是完全任意的,并且可能是预先存在的)
编辑结束
例如,考虑:
def f(x,y,z):
return x + 2*y + 3*z
然后,使用
from functools import partial
两者
partial(f,4)(5,6)
和
partial(f,4,5)(6)
给32。
但是如果要计算第三个参数 z
或第一个和第三个参数 x
以及 z
怎么办?
有没有方便的方法将位置信息传递给partial
,使用decorator
或dict
,其键是所需的arg位置,各自的值是arg价值观?例如传递 x
和 z
位置是这样的:
partial_dict(f,{0:4,2:6})(5)
只需使用关键字参数。使用上面 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
module documentation
中给出的 functools.partial
的伪实现
不,partial
不是为了在非连续位置冻结位置参数而设计的。
要实现问题中概述的所需行为,您必须想出一个自己的包装函数,如下所示:
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))
输出:
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, 4, SKIP, 6)(5))
输出:
32
根据手册,functools
partial()
是 'used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature.'
指定要计算的参数位置的最佳方法是什么?
编辑
请注意,根据评论,要部分评估的函数可能包含命名和未命名的参数(这些函数应该是完全任意的,并且可能是预先存在的)
编辑结束
例如,考虑:
def f(x,y,z):
return x + 2*y + 3*z
然后,使用
from functools import partial
两者
partial(f,4)(5,6)
和
partial(f,4,5)(6)
给32。
但是如果要计算第三个参数 z
或第一个和第三个参数 x
以及 z
怎么办?
有没有方便的方法将位置信息传递给partial
,使用decorator
或dict
,其键是所需的arg位置,各自的值是arg价值观?例如传递 x
和 z
位置是这样的:
partial_dict(f,{0:4,2:6})(5)
只需使用关键字参数。使用上面 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
module documentation
functools.partial
的伪实现
不,partial
不是为了在非连续位置冻结位置参数而设计的。
要实现问题中概述的所需行为,您必须想出一个自己的包装函数,如下所示:
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))
输出:
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, 4, SKIP, 6)(5))
输出:
32