Python 闭包与函数属性

3 投票
3 回答
747 浏览
提问于 2025-04-17 11:08

我尝试重新实现一个类似于 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 个回答

0

functools.partial 可以在返回的内部函数中接受额外的参数,或者覆盖一些参数。而你内部的 f() 函数并不需要这些,所以在 lazycall2 中你做的事情其实没必要。不过,如果你想做类似的事情:

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

那么你就需要按照文档中展示的那样去做。

0

仔细看看你提到的Python文档中,内部函数newfunc的参数名称,它们和传给这个内部函数的参数名称是不同的,比如argsfargs,还有keywordsfkeywords。他们实现的partial功能是保存外部函数传入的参数,并把这些参数加到内部函数接收到的参数中。

因为你在内部函数中使用了完全相同的参数名称,所以外部函数传入的原始参数在内部函数里是无法访问的。

至于在外部函数上设置funcargskwargs属性,Python中的函数其实也是一种对象,你可以在它上面设置属性。这些属性让你在把它们传入lazycall函数后,仍然能访问到原始的函数和参数。所以a1.func会是A,而a1.args会是[1]

如果你不需要跟踪原始的函数和参数,那么使用你的lazycall1就没问题。

2

第二种形式唯一多出来的就是一些额外的属性。如果你开始传递lazycall2返回的函数,这些属性可能会很有用,因为接收这些函数的地方可以根据这些属性的值做出一些决定。

撰写回答