我是否应该返回通过引用传递并修改过的列表?

更新时间:2023-04-02 11:41:33

问题阐述

我最近发现,Python中的列表是通过引用自动传递的(除非使用符号数组[:])。例如,这两个函数执行相同的操作:

def foo(z):
    z.append(3)

def bar(z):
    z.append(3)
    return z

x = [1, 2]
y = [1, 2]
foo(x)
bar(y)
print(x, y)

在此之前,我总是返回我操作过的数组,因为我认为我必须这样做。现在,我知道这是多余的(可能效率很低),但返回值似乎通常是代码可读性的良好实践。我的问题是,做这两种方法中的任何一种都有什么问题吗/最佳实践是什么?有没有我错过的第三个选择?如果以前有人问过这个问题,我很抱歉,但我找不到任何真正回答我问题的东西。

精准答案

此答案的前提是已经决定是就地修改您的输入还是返回副本。

正如您所提到的,是否返回修改后的对象是见仁见智的,因为结果在功能上是等价的。通常,NOT返回就地修改的列表被认为是一种好的形式。根据Zen of Python(第二项):

显式优于隐式。

这一点在标准库中得到了证实。List方法因此而臭名昭着:list.append, insert, extendlist.sort等。

Numpy也经常使用这种模式,因为它经常处理复制和返回不切实际的大型数据集。一个常见的例子是数组方法numpy.ndarray.sort,不要与返回新副本的顶级函数numpy.sort混淆。

这个想法在很大程度上是Python思维方式的一部分。以下是Guido's email的摘录,解释了原因:

我发现链接对可读性构成了威胁;它要求读者必须非常熟悉每种方法。第二个[未链接]形式清楚地表明,这些调用中的每个都作用于同一个对象,因此即使您不太了解类及其方法,您也可以理解第二个和第三个调用应用于x(并且所有调用都是为了它们的副作用),而不是应用于其他对象。