Python中连续多括号调用函数与类的运行原理是什么
链式多括号调用的核心原理
这种连续写括号传参的调用形式,本质依赖Python的可调用对象规则:
- 只要对象实现了
__call__方法(普通函数、闭包、自定义类实例都属于这类),就能通过对象(参数)的形式执行 - 每次调用后如果返回值仍然是可调用对象,就可以继续往后追加括号传参;如果返回整数、字符串这类普通不可调用值,链式调用就终止,拿到最终结果。
闭包版
chain_sum运行逻辑 这个版本用Python闭包特性实现累计状态的保存,逐段拆解逻辑:
- 外层函数
chain_sum接收初始求和值,把值存在作用域变量result中,定义内部函数wrapper后,直接把wrapper函数对象返回 - 内部
wrapper函数的执行逻辑:- 定义可选参数
number_2,默认值为None - 调用时如果没传参(
number_2 is None),直接返回闭包中保存的累计值result,此时返回的是整数,不可继续调用,链式终止 - 调用时如果传了有效数值,就把值累加到
result上,返回wrapper函数本身——因为返回值还是可调用的函数,所以可以继续加括号传入下一个累加值
- 定义可选参数
- 这里的
nonlocal关键字作用是声明:wrapper内部用到的result不是当前函数的局部变量,要去外层chain_sum的作用域查找,保证累加操作修改的是闭包内持久保存的累计值,不会新建局部变量。
举个完整执行例子,对应chain_sum(5)(100)(-10)()的运行步骤:
- 第一步执行
chain_sum(5):初始化result=5,返回wrapper函数,此时表达式等价于wrapper - 第二步执行
wrapper(100):传入参数100,result更新为5+100=105,返回wrapper本身,表达式仍等价于wrapper - 第三步执行
wrapper(-10):传入参数-10,result更新为105-10=95,返回wrapper本身,表达式仍等价于wrapper - 第四步执行
wrapper():未传参数,直接返回result=95,拿到最终结果
继承int的类版本
chain_sum_0运行逻辑 这个版本是在内置整数类的基础上扩展可调用能力,逻辑更巧:
chain_sum_0继承自Python内置的int类,所以它的实例本身就是一个整数,直接打印、参与运算都和普通整数没有区别,比如chain_sum_0(5)本身就是值为5的整数对象,不需要加空括号就能直接使用- 它重写了
__call__方法,让整数实例变成可调用对象:当给实例加括号传参时,会把当前实例的整数值和传入的累加值相加,再把相加结果传给前面的闭包版chain_sum,拿到返回的wrapper闭包,后续的链式调用逻辑就和闭包版完全一致。
两个版本的使用差异:闭包版必须在最后加一个空括号才能拿到最终数值,否则拿到的只是
wrapper函数对象;类版本不需要强制加空括号,不需要继续累加时可以直接当普通整数使用。
内容的提问来源于stack exchange,提问作者Kirill Meha
相关产品推荐
相关产品推荐

