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

Python递归函数调用中列表与整数参数的行为差异疑问

为什么两个Python递归函数的行为存在差异?

我编写了两个Python递归函数:

def test_list(outcome=[1]):
    outcome += [2*outcome[-1]]
    print(outcome)
    if outcome[-1] < 8:
        test_list(outcome)
    print(outcome)
def test_integer(n=1):
    n *= 2
    print(n)
    if n < 8:
        test_integer(n)
    print(n)

函数行为对比

  • test_integer()的输出符合预期:

    2
    4
    8
    8
    4
    2
    

    这是因为整数是不可变类型,执行n *= 2时,并不是修改原有整数对象的值,而是创建一个新的整数对象并让当前层的n指向它。上层递归中的n依然指向原来的整数对象,不受下层操作影响,所以回溯时会依次打印各层自己的n值。

  • test_list()的实际输出与预期不符:
    预期输出:

    [1, 2]
    [1, 2, 4]
    [1, 2, 4, 8]
    [1, 2, 4, 8]
    [1, 2, 4]
    [1, 2]
    

    实际输出:

    [1, 2]
    [1, 2, 4]
    [1, 2, 4, 8]
    [1, 2, 4, 8]
    [1, 2, 4, 8]
    [1, 2, 4, 8]
    

核心原因:可变与不可变对象的传参特性

Python中参数传递是按对象引用传递,但可变对象和不可变对象的表现完全不同:

  1. 不可变对象(如整数、字符串、元组):
    无法修改原有对象的内容,任何看似“修改”的操作都会创建新对象。所以每层递归的n都是独立的对象,下层修改不会影响上层。

  2. 可变对象(如列表、字典):
    可以直接修改原有对象的内容。test_list中,outcome += [...]是在原列表对象上追加元素,递归调用时传递的也是这个列表的引用——所有递归层操作的都是同一个列表对象。当递归回溯时,这个列表已经被修改为最终的[1, 2, 4, 8],所以每次打印的都是这个最终状态的列表。

另外需要注意:test_list的默认参数outcome=[1]是在函数定义时初始化的(只执行一次),不过这里递归调用时主动传入了outcome,所以核心差异还是源于列表的可变性。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 10:07:38