在官方文档中10.2. functools 关于部分
大致相当于:
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*args, *fargs, **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
我想如果把它重构为:
可能会更好def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
return func(*args, *fargs, **fkeywords, **keywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
或
def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newargs = args.copy()
newkeywords.update(fkeywords)
args.append(fargs)
return func(*args, **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
我的假设是否有意义?
答案 0 :(得分:2)
你的第一个版本不太合适,因为the docs解释了:
如果提供了其他关键字参数,它们会扩展和覆盖关键字。
当您执行两个关键字splats时,就像在您的版本中一样,您不会覆盖重复的关键字;相反,您会得到TypeError
,如Calls
中所述:
如果语法**表达式出现在函数调用中,则表达式必须求值为映射,其内容被视为附加关键字参数。如果关键字已经存在(作为显式关键字参数,或来自另一个解包),则会引发TypeError异常。
比较
>>> def sub(a, b): return a-b
>>> sub2 = functools.partial(sub, b=2)
>>> sub2(5, b=0)
5
>>> sub2 = partial(sub, b=2)
>>> sub2(5, b=0)
TypeError: f() got multiple values for keyword argument 'b'
您的第二个版本不起作用有四个原因:
*args
是一个元组,而元组没有copy
。不可改变,很少有理由复制它们。append
,是不可变的。append
也会将新参数列表作为单个参数添加到结尾,但是您希望将它们全部添加为单独的参数。这就是extend
的用途。args
代替newargs
。您可以通过执行以下操作来解决所有问题:
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newargs = list(args)
newkeywords.update(fkeywords)
newargs.extend(fargs)
return func(*newargs, **newkeywords)
但是更简单(也更有效)的方式是:
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
newargs = args + fargs
return func(*newargs, **newkeywords)
事实上,在Python允许多个splats在3.5中的单个调用之前,这与partial
之前的文档非常接近。在3.4和2.7:
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
唯一的区别是他们直接在splat中执行args + fargs
,而不是将其分配给newargs
变量。