为何Python函数会修改传入的列表参数?AoC2022 Day5问题求助
问题:Python列表传入函数后原列表被修改的原因
我在完成Advent of Code 2022第5天题目时遇到一个问题:把stacks列表传入A.py的calculate函数后,原列表居然被修改了,导致后续B.py运行出错。我通过将列表转为元组再转回列表的显式拷贝方式解决了问题,但想知道Python这种行为的原因,这是不是语言的内置特性?
相关代码
main.py
import A import B with open("input.txt", "r") as file: data = [_ for _ in file.read().split("\n")] stacks = [] controls = [] stackData = data[:8] for i in range(9): stack = "" for row in stackData: box = row[(i*4 + 1)] stack += box stacks.append(stack) for i in range(len(stacks)): stacks[i] = stacks[i].strip() controlData = data[10:] for row in controlData: control = row.split(" ") amount = int(control[1]) spot = int(control[3]) destination = int(control[5]) controls.append([amount, spot, destination]) print(f"Answer to section A is: {A.calculate(stacks, controls)}") print(f"Answer to section B is: {B.calculate(stacks, controls)}")
A.py
def calculate(data, controls): answer = "" for control in controls: amount = control[0] start = control[1] - 1 destination = control[2] - 1 boxes = data[start][:amount] boxes = boxes[::-1] data[start] = data[start][amount:] data[destination] = boxes + data[destination] for stack in data: answer += stack[0] return answer
B.py
def calculate(data, controls): answer = "" for control in controls: amount = control[0] start = control[1] - 1 destination = control[2] - 1 boxes = data[start][:amount] data[start] = data[start][amount:] data[destination] = boxes + data[destination] for stack in data: answer += stack[0] return answer
解答
这是Python的内置特性,核心原因在于:
- 列表是可变对象:Python中的列表属于可变类型,意味着可以在原对象上直接修改内容(比如修改元素、增删元素等)。
- 参数传递是引用传递:当你把
stacks传入函数时,函数参数data拿到的是原列表对象的引用——也就是说,data和stacks指向内存中同一个列表。
在A.py的calculate函数里,你执行了data[start] = data[start][amount:]、data[destination] = boxes + data[destination]这类操作,这些都是直接修改data指向的列表对象内容,自然会影响到外部的stacks。等A的计算完成,stacks已经是被修改后的状态,再传入B.py的calculate时,用的是修改后的列表,结果必然出错。
你用“转元组再转回列表”的方式解决问题,本质是创建了原列表的浅拷贝——新列表和原列表是两个独立的对象,函数里修改的是拷贝后的列表,不会影响原列表,这样B就能使用原始的stacks计算了。
类似的浅拷贝方式还有:
- 使用列表切片:
stacks[:] - 使用
copy模块:import copy; copy.copy(stacks) - 列表自身的
copy方法:stacks.copy()
因为你的列表元素是字符串(不可变类型),浅拷贝就足够保证两个列表完全独立。如果列表里还有可变子对象,可能需要用到深拷贝copy.deepcopy()。
内容的提问来源于stack exchange,提问作者Zach Tydeman
相关产品推荐
相关产品推荐

