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中参数传递是按对象引用传递,但可变对象和不可变对象的表现完全不同:
不可变对象(如整数、字符串、元组):
无法修改原有对象的内容,任何看似“修改”的操作都会创建新对象。所以每层递归的n都是独立的对象,下层修改不会影响上层。可变对象(如列表、字典):
可以直接修改原有对象的内容。test_list中,outcome += [...]是在原列表对象上追加元素,递归调用时传递的也是这个列表的引用——所有递归层操作的都是同一个列表对象。当递归回溯时,这个列表已经被修改为最终的[1, 2, 4, 8],所以每次打印的都是这个最终状态的列表。
另外需要注意:test_list的默认参数outcome=[1]是在函数定义时初始化的(只执行一次),不过这里递归调用时主动传入了outcome,所以核心差异还是源于列表的可变性。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

