为何两段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
相关产品推荐
相关产品推荐

