为什么Python的functools.partial定义使用函数属性?

gorkyyrv  于 2022-12-20  发布在  Python
关注(0)|答案(3)|浏览(111)

在functools.partial示例定义中,函数属性用在返回的partial函数对象中:

def partial(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

如果这些属性被移除,会有什么潜在的问题呢?如果newfunc还活着,Python不应该保留对func、args和keywords的引用吗?

def partial(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    return newfunc

我知道functools.partial的实际实现可能完全不同,但是如果它是这样实现的,为什么属性是必需的呢?

x33g5p2x

x33g5p2x1#

任何实现都需要将函数及其固定参数存储在某个地方。在您的两个示例中,我们使用了闭包。当这些partial实现返回时,这些值将被添加到返回的闭包中。在这种情况下,.func.args.keywords是冗余的。闭包已经有了它们。因此,使用选项2。
但是python为这项工作创建了一个类,.func.args.keywords是所需数据的唯一副本,类的实现允许你以一种有效的方式(它结合了两个partial的参数)创建partial的partial,并且在构建对象的字符串显示时更整洁。
但是你的第二个关闭机制是好的,只是做事情的方式不同。

hec6srdp

hec6srdp2#

由于partial实际上是一个类型,因此提供一个等效的 class 比将其转换为函数更有意义。

class partial:
    def __init__(self, func, /, *args, **kwargs):
        self.func = func
        self.args = args
        self.keywords = kwargs

    def __call__(self, *args, **kwargs):
        new_keywords = {**self.keywords, **kwargs}
        return self.func(*self.args, *args, **new_keywords)

注意,所有被赋值给函数属性的东西现在都被赋值给self的示例属性。当你调用partial的示例时,你调用的是原始函数,保存的参数与“immediate”参数合并。

def foo(a, b, c):
    ...

p = partial(foo, 3, c=9)
p(5)  # Equivalent to foo(3, 5, 9)

至于为什么文档使用函数,也许人们认为嵌套函数比解释__call__的作用要简单?
这个函数使用函数属性而不是闭包,正是因为partial的实际实现也将保存的参数存储在名为argskeywords的属性中,毕竟它们试图模拟真实的类型。

gopyfrb3

gopyfrb33#

显然,函数属性在分部函数的实现中实际上并不是必需的,只是因为API需要才添加它们,这里有两组变量:一个是在newfunc的闭包中,另一个是以属性的形式,newfunc不使用这些属性。
感谢@juanpa.arrivillaga的澄清。

相关问题