在将 list/dict 传递给函数时,是否应该始终添加 list.copy() / dict.copy()?

Should you always add list.copy() / dict.copy() when passing a list/dict to a function?

我今天有一个痛苦的经历,我不小心将一个列表传递给了一个函数,并且花了我很长时间来调试。该功能旨在接收列表并创建类似列表的副本。我没有意识到这修改了我原来的列表。

L = [0,0,0,0,0]

def similar_list(a_list):
    a_list [0] = a_list[0]+1
    return a_list

L_similar = similar_list(L)
print(L)
print(L_similar)

#result shows
#[1, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]

我认为最好的方法是在similar_list函数的第一行,添加a_list = a_list.copy()。有更好的方法吗?我问的是在我对 python 的有限研究中,我不记得在示例代码中经常看到这个。如果您能告诉我这是否是标准做法,我们将不胜感激。 (不过,这似乎是一件很容易出错的事情,当出错时很难注意到..)

您可以使用 L_similar = similar_list(L[:]) 而不是使用 L_similar = similar_list(L) 来避免对原始列表进行任何更改。

试试这个:

L = [0,0,0,0,0]

def similar_list(a_list):
    a_list [0] = a_list[0]+1
    return a_list

L_similar = similar_list(L[:])
print(L)
print(L_similar)

#result shows
#[0, 0, 0, 0, 0]
#[1, 0, 0, 0, 0]

[编辑]:

然而,L[:]L.copy() 两种方法都将 return 列表的浅拷贝。这意味着如果您修改任何嵌套列表元素,更改将反映在两个列表中。考虑以下示例:

L = [1, [2, 3], 4]
L_copy = L.copy()

L[1][0] = 5

print(L)
print(L_copy)

#result shows
#[1, [5, 3], 4]
#[1, [5, 3], 4]

为避免此问题,您应该使用 copy 模块中的 copy.deepcopy()

import copy

L = [1, [2, 3], 4]
L_copy = copy.deepcopy(L)

L[1][0] = 5

print(L)
print(L_copy)

#result shows
#[1, [5, 3], 4]
#[1, [2, 3], 4]

这完全取决于 similar_list() 应该做什么。

如果您打算修改原始列表,只需像您看到的那样就地更改它:

def similar_list(a_list):
    a_list[0] += 1

如您所见,我没有 return 原始列表。根据 Python's convention,修改输入对象的函数或方法,不要 return 它以避免混淆并更清楚。

如果你打算return一个新的列表,它有很多与不变性相关的优点,你可以复制然后修改:

def similar_list(a_list):
    newlist = a_list.copy()
    newlist[0] += 1
    return newlist

如果您需要复制,这是一种标准做法,但最终由您决定。

对于一些优缺点,您可以参考 Python 在 functional programming 上的官方指南。