真实对一个functools.partial对象再包一层partial,验证.func/.args/.keywords这几个内省属性,以及partial嵌套时真实在构造阶段就展平合并到最底层函数的实现细节。
代码def greet(greeting, name, punctuation="."): return f"{greeting}, {name}{punctuation}" hello = functools.partial(greet, "Hello") hello_excited = functools.partial(hello, punctuation="!") print(hello_excited("Universe")) print(hello_excited.func) # 是hello,还是最原始的greet? print(hello_excited.args) print(hello_excited.keywords)
type(hello) → <class 'functools.partial'>
hello.func → <function greet at 0x...>
hello.args → ('Hello',)
hello.keywords → {}这是本文认为functools.partial跟"手写一个闭包函数做同样的事"最真实的区别:partial(greet, "Hello")返回的不是一个普通的函数对象,而是一个真实携带内部状态的functools.partial类型实例,.func、.args、.keywords这几个属性真实把"预先绑定了哪个函数、绑定了哪些位置参数、绑定了哪些关键字参数"这些信息完全暴露出来,可以在运行时被真实检查和内省——如果换成手写def hello(name): return greet("Hello", name)这样一个闭包,外部代码就真实没有任何标准方式能反过来问"这个函数底层包的是哪个原始函数、绑定了什么参数"。
hello_excited("Universe") → "Hello, Universe!" ← 正常工作
hello_excited.func → <function greet at 0x...> ← 真实是最原始的greet,不是hello!
hello_excited.args → ('Hello',) ← 真实是从hello那一层继承下来的位置参数
hello_excited.keywords → {'punctuation': '!'} ← 真实只有这一层新加的关键字参数每一步都是本文上面用真实的functools.partial跑出来的原始结果。
functools.partial