Python函数内对传入列表执行append操作后是否需要返回该列表?
两种写法都不是最优实践,问题的核心从来不是「要不要return被修改的列表」,而是你是否应该在函数内部直接修改传入的可变对象,返不返回只是这个核心选择下的惯例适配问题。
两种写法的问题分别在哪
1. 直接修改入参、不返回值的写法
这种写法本质是给函数加了隐式副作用:如果调用方不逐行读函数内部实现,很可能根本意识不到自己传进去的列表会被悄悄改动。在代码量小、只有你一个人开发的时候可能没问题,但一旦项目规模变大、多人协作,这种隐式修改会成为bug重灾区——比如同一个列表被传给3个不同函数,每个函数都偷偷改它,排查数据异常的时候你根本找不到是谁动的手。
但这种写法本身是符合Python标准库设计惯例的:Python所有原地修改可变对象的内置方法,都不会返回原对象,而是返回None,比如list.append()、list.sort()、dict.update()全是这个逻辑。这个设计是故意的,就是为了给调用方明确信号:这个操作是原地修改,不会生成新对象。
2. 原地修改入参后再return原列表的写法
非常不推荐这种写法,它完全违背了Python开发者的普遍共识:大家默认只要函数/方法有返回值,返回的一定是新生成的对象,原入参不会被改动,比如sorted(xxx)、列表推导式生成新列表全是这个逻辑。
如果你既改了原列表,又把原列表return回来,非常容易误导调用方——比如有人写result_list = add_new_number_squared(2, origin_list),他大概率会以为origin_list还保持原样,返回的是处理后的新列表,结果实际用的时候才发现原列表早就被改了,反而比不返回更容易出问题。
推荐的实践方案
根据你的实际需求二选一即可:
- 如果就是明确要做原地修改的逻辑:那就保持第一种写法,不要return值,和内置方法的行为保持一致。最好在函数命名上就明确标识出原地修改的属性,比如把函数名改成
append_squared_number_inplace,调用方看到名字就知道传进去的列表会被改动,从根源上减少误解。 - 如果不想引入隐式副作用(绝大多数业务场景更推荐这种):那就不要碰传入的原列表,在函数内部创建副本做处理,最后返回处理完的新列表,参考写法:
def add_new_number_squared(new_number, numbers_list): # 先拷贝原列表,不修改入参 result = numbers_list.copy() result.append(new_number**2) return result my_list = [0] # 原列表my_list不会被改动,返回的是新列表 new_list = add_new_number_squared(2, my_list)
这种写法没有任何隐式副作用,调用方不管怎么传参都不会出现意外的数据改动,返回新对象的行为也完全符合开发者的普遍预期,排查问题的成本低很多。
另外顺便提一句,你贴的第一版示例代码有个笔误:append里写的是num**2,但函数里根本没定义num变量,运行会直接抛NameError,正确的变量名应该是入参new_number。
内容的提问来源于stack exchange,提问作者cholo14

