我不知道这里出了什么问题,但我确信这里有人可以提供帮助。我有一个列表mylst(列表的列表),它被复制并传递到方法中foo。 foo遍历列表并用传入的变量替换行中的第一个元素并返回更改后的列表。我打印列表,看到它给了我期望的结果。我用另一个副本mylst和不同的传入变量再次重复该过程。所以两个返回的列表应该不同;但是当我再次检查第一个列表时,我发现它现在是第二个列表,也mylst已更改为第二个列表。我复制列表的方式不正确吗?我正在用mylst[:]方法复制它。另一个有趣的观察是所有列表 ID 都不同。这难道不意味着它与其他列表不同吗?这是我的问题的一个例子。
mylst
foo
mylst[:]
def printer(lst): print "--------------" for x in lst: print x print "--------------\n" def foo(lst, string): for x in lst: x[0] = string print "in foo" for x in lst: print x print "in foo\n" return lst mylst = [[1, 2, 3], [4, 5, 6]] print "mylst", id(mylst), "\n" first = foo(mylst[:], "first") print "first", id(first) printer(first) # Correct second = foo(mylst[:], "second") print "second", id(second) printer(second) # Correct print "first", id(first) printer(first) # Wrong print "mylst", id(mylst) printer(mylst) # Wrong
这是我电脑上的打印件
mylst 3076930092 in foo ['first', 2, 3] ['first', 5, 6] in foo first 3076930060 -------------- ['first', 2, 3] ['first', 5, 6] -------------- in foo ['second', 2, 3] ['second', 5, 6] in foo second 3076929996 -------------- ['second', 2, 3] ['second', 5, 6] -------------- first 3076930060 -------------- ['second', 2, 3] ['second', 5, 6] -------------- mylst 3076930092 -------------- ['second', 2, 3] ['second', 5, 6] --------------
问题出在您使用 mylst[:] 创建副本的方式上。mylst[:] 会执行 浅拷贝,即它创建了一个新的外层列表对象,但内层列表(mylst 中的行)仍然是原始内层列表的引用。
因此,当 foo 修改列表中的行时,它会影响到原始 mylst 和其他副本,因为它们共享相同的内层列表引用。
为什么列表 ID 不同:
first
second
[1, 2, 3]
[4, 5, 6]
为了避免这个问题,您需要创建 深拷贝,即不仅复制外层列表,还复制其内层列表。以下是两种解决方案:
copy
copy.deepcopy 会递归复制所有层级的数据结构。
copy.deepcopy
import copy def foo(lst, string): for x in lst: x[0] = string return lst mylst = [[1, 2, 3], [4, 5, 6]] first = foo(copy.deepcopy(mylst), "first") print("first") for x in first: print(x) second = foo(copy.deepcopy(mylst), "second") print("second") for x in second: print(x) print("mylst") for x in mylst: print(x)
first ['first', 2, 3] ['first', 5, 6] second ['second', 2, 3] ['second', 5, 6] mylst [1, 2, 3] [4, 5, 6]
如果不想使用 copy.deepcopy,可以通过列表推导式手动创建新的内层列表:
mylst_copy = [row[:] for row in mylst]
在您的代码中:
first = foo([row[:] for row in mylst], "first") second = foo([row[:] for row in mylst], "second")
这是因为 Python 的列表存储的是对其元素的引用,而不是实际的数据副本。例如:
mylst = [[1, 2, 3], [4, 5, 6]] shallow_copy = mylst[:] # 修改 shallow_copy 的第一个内层列表 shallow_copy[0][0] = "modified" # 这也会影响到 mylst print(mylst) # [['modified', 2, 3], [4, 5, 6]]
深拷贝可以确保新列表中的所有对象都是独立的副本。
[row[:] for row in mylst]