Python闭包和函数属性

3
我尝试重新实现类似于“partial”的东西(稍后将具有更多行为)。现在在以下示例中,“lazycall1”似乎与“lazycall2”一样正常工作,因此我不明白为什么“partial”的文档建议使用更长的第二个版本。有什么建议吗?这会给我带来麻烦吗?
def lazycall1(func, *args, **kwargs):
    def f():
        func(*args, **kwargs)
    return f

def lazycall2(func, *args, **kwargs):
    def f():
        func(*args, **kwargs)
    f.func=func   # why do I need that?
    f.args=args
    f.kwargs=kwargs
    return f

def A(x):
    print("A", x)

def B(x):
    print("B", x)

a1=lazycall1(A, 1)
b1=lazycall1(B, 2)
a1()
b1()

a2=lazycall2(A, 3)
b2=lazycall2(B, 4)
a2()
b2()

编辑:实际上,到目前为止提供的答案都不是完全正确的。即使使用双重参数,它也可以工作。还有其他原因吗?

def lazycall(func, *args):
    def f(*args2):
        return func(*(args+args2))
    return f

def sum_up(a, b):
    return a+b

plusone=lazycall(sum_up, 1)
plustwo=lazycall(sum_up, 2)
print(plusone(6)) #7
print(plustwo(9)) #11
3个回答

2
第二种形式唯一的额外之处在于它具有一些额外的属性。如果您开始传递由lazycall2返回的函数,那么这可能很有帮助,以便接收函数可以基于这些值做出决策。

0

functools.partial可以在内部返回的函数中接受额外的参数或覆盖参数。您的内部f()函数不需要这样做,因此在lazycall2中所做的工作是没有必要的。但是,如果您想要做类似于以下内容的操作:

def sum(a, b):
    return a+b
plusone = lazycall3(sum, 1)
plusone(6) # 7

你需要按照这些文档所示的方式去操作。


这不会有任何影响。我用一个更一般的例子编辑了我的问题。这样正确吗? - Gere
functools.partial 返回的对象具有 .func.keywords.func 属性。文档展示了一种在纯 Python 中模拟它的方法。但是,不会影响返回对象的调用 - 它只会使最初传递的函数和参数在返回的对象上可访问。 - AdamKG

0

在你链接的Python文档页面中,仔细查看内部函数newfunc中的参数名称,它们与传递给内部函数的参数名称不同,argsfargskeywordsfkeywords。他们对partial的实现保存了外部函数所给定的参数,并将它们添加到传递给内部函数的参数中。

由于您在内部函数中重用了完全相同的参数名称,因此无法在其中访问外部函数的原始参数。

至于在外部函数上设置funcargskwargs属性,函数在Python中是一个对象,您可以在其上设置属性。这些属性允许您在将它们传递到您的lazycall函数之后访问原始函数和参数。因此,a1.func将是Aa1.args将是[1]

如果您不需要跟踪原始函数和参数,那么使用您的lazycall1就可以了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接