You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python递归调用传递列表参数时不同写法结果差异问题咨询

问题解答

核心原因

两种写法的差异本质是Python变量赋值时机、表达式从左到右的求值规则,以及可变对象修改/重绑定的区别共同导致的。

f1与f2的差异细节

f1的执行逻辑

f1将两次递归调用拆分到了两个独立的赋值语句中:

# 第一次赋值:执行完第一个递归调用后,立刻更新l1变量的指向
l1 = [*l1, *f1(l1, num-1)]
# 第二次赋值:传入的l1已经是第一次更新后的值
l1 = [*l1, *f1(l1, num -1)]

执行顺序是:

  1. 调用第一个f1(l1, num-1),拿到返回值
  2. 解包生成新列表,赋值给当前作用域的l1变量,此时l1已经指向修改后的新列表
  3. 调用第二个f1(l1, num-1),传入的是更新后的l1,所以第二次调用能拿到第一次修改的结果。

f2的执行逻辑

f2将两次递归调用写在了同一个列表构造表达式中:

l1 = [*l1, *f2(l1, num-1),*f2(l1, num -1)]

Python表达式严格按照从左到右的顺序求值,所有子表达式求值完成后才会执行最终的赋值操作,执行顺序是:

  1. 先读取当前l1的值(初始值,还没被修改)
  2. 调用第一个f2(l1, num-1),传入初始的l1,函数内部的l1赋值是局部变量重绑定,不会修改外层作用域传入的原列表对象,调用完成后外层的l1还是初始值
  3. 调用第二个f2(l1, num-1),传入的还是初始的l1,所以两次调用的入参完全相同
  4. 所有子表达式求值完成后,才将最终构造的新列表赋值给l1,因此第二次递归调用拿不到第一次的修改结果。

f3的特殊情况说明

f3和f2的核心区别是:f3是原地修改列表对象,而不是重绑定变量:

def f3(l1):
    print(l1)
    l1 +=[1] # += 对于列表是原地修改操作,直接改变原对象的内容,不是生成新列表重绑定变量
    return l1

执行顺序是:

  1. 第一个f3(l1)调用时,直接修改了传入的原列表对象的内容,此时l1指向的对象本身已经发生变化
  2. 第二个f3(l1)调用时,传入的还是同一个列表对象,因此能看到前一次调用的修改结果
  3. 所有子表达式求值完成后,才构造新列表赋值给外层的l1。

f2的递归调用中没有修改最初传入的原列表对象,只是函数内部给局部变量绑定了新的列表,因此前一次调用的修改不会影响后续同表达式内的调用入参,和f3的场景有本质区别。


内容的提问来源于stack exchange,提问作者Аркадий Момосов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:45:03