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

为何两段Python列表递归反转代码执行结果存在差异?

为什么两段反转列表的递归代码对原列表的影响不同?

咱们来一步步拆解这两段代码的核心差异,本质是Python中可变对象的引用传递、局部变量赋值与原地修改的区别。

第一段代码:原列表未被修改的原因

先看这段代码:

s = ["h", "e", "l", "l", "o"]
def reverse(s):
    if len(s) == 0:
        return
    if len(s) == 1:
        return s;
    temp = s[0]
    s = reverse(s[1:])  # 关键操作
    s.append(temp)
    return s
print(reverse(s))
print(s)

这里的核心问题出在切片操作和局部变量重新赋值:

  • 当调用reverse(s[1:])时,s[1:]会生成原列表的一个新切片副本,递归过程中处理的都是这些副本,而非原列表本身。
  • 接下来的s = reverse(...)是把递归返回的新列表赋值给函数内部的局部变量s,这个局部变量和外部全局的s已经是两个完全不同的引用——它们指向内存中两个独立的列表对象。
  • 最后返回的是新构建的反转列表,但外部原列表自始至终没有被任何原地修改方法(比如append、pop)操作过,所以打印出来还是初始状态。

简单说:这段代码是创建了一个新的反转列表返回,原列表根本没被改动过。

第二段代码:原列表被直接修改的原因

再看这段代码:

s = ["h", "e", "l", "l", "o"]
def reverse(s, index):
    if index >= len(s) or len(s) == 0:
        return
    reverse(s, index + 1)
    s.insert((len(s) - 1 - index), s.pop())  # 关键操作
reverse(s, 0)
print(s)

这段代码的核心是原地修改可变对象:

  • Python中,列表是可变对象,当你把列表作为参数传递给函数时,传递的是对象的引用。函数内部的s和外部的s指向内存中同一个列表对象。
  • 函数里没有对s进行重新赋值(没有s = ...这种操作),所有操作都是直接在这个共享的列表对象上进行:s.pop()会原地删除列表最后一个元素,s.insert(...)会原地插入元素——这些都是原地修改列表的方法,会直接改变原对象的内容。
  • 递归过程中每一层操作的都是同一个原列表,所以最终原列表被反转了。

总结一下

  • 如果函数内没有重新赋值参数变量,而是用原地修改方法操作可变对象(列表、字典等),外部的原对象会被改变。
  • 如果函数内对参数变量进行了重新赋值(比如s = ...),参数变量会指向新对象,和外部原变量的引用断开,后续操作不会影响原对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:57:01