在官方文档中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


我的假设有意义吗?

最佳答案

您的第一个版本不太有效,因为如the docs所述:


  如果提供了其他关键字参数,它们将扩展并覆盖关键字。


当您像在您的版本中那样执行两个关键字splat时,您不会覆盖重复的关键字。相反,您会得到一个TypeError,如Calls中所述:


  如果语法** expression出现在函数调用中,则表达式必须计算为一个映射,该映射的内容被视为其他关键字参数。如果已经存在一个关键字(作为显式关键字参数,或来自另一个拆包),则会引发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)


实际上,这与partial在Python在3.5中的单个调用中允许多个splats之前的文档非常接近。在3.42.7中:

def newfunc(*fargs, **fkeywords):
    newkeywords = keywords.copy()
    newkeywords.update(fkeywords)
    return func(*(args + fargs), **newkeywords)


唯一的区别是它们直接在splat中执行args + fargs,而不是将其分配给newargs变量。

09-19 06:01