可能重复:
Python将列表作为参数传递
我找了很多关于这方面的话题,但我不明白到底发生了什么。
我有这个代码:
def altera(L1, L2):
for elemento in L2:
L1.append(elemento)
L2 = L2 + [4]
L1[-1] = 10
del L2[0]
return L2[:]
Lista1 = [1,2,3]
Lista2 = [1,2,3]
Lista3 = altera(Lista1, Lista2)
print Lista1
print Lista2
print Lista3
结果是:
[1, 2, 3, 1, 2, 10]
[1, 2, 3]
[2, 3, 4]
我不明白Lista1
是怎么修改的,而Lista2
不是。然而,在测试代码之前,我认为Lista1
和Lista2
将保持不变,因为它们是全局变量。
列表在Python中通过引用传递。Lista1
被修改是因为您直接调用.append
:
for elemento in L2:
L1.append(elemento)
未修改Lista2
,因为您未修改列表。您使用了加法运算符L2 = L2 + [4]
,不会修改L2
。相反,它会创建一个新列表并返回结果。
如果你在谷歌上搜索术语"pass-by-reference",你应该能够在Python中找到一些很好的解释性例子。
执行L1.append(elemento)
时,调用的方法实际上会更改由变量L1
命名的列表。设置L1
和L2
值的所有其他命令实际上只是为新变量创建新名称。
这个版本不会改变任何东西:
def altera(L1, L2):
for elemento in L2:
# create a new list and assign name L1
L1 = L1 + [elemento]
# create a new list and assign name L2
L2 = L2 + [4]
return L2
Lista1 = [1,2,3]
Lista2 = [1,2,3]
Lista3 = altera(Lista1, Lista2)
print Lista1
print Lista2
print Lista3
而这一个是:
def altera(L1, L2):
for elemento in L2:
# Call method on L1 that changes it
L1.append(elemento)
# Call method on L2 that changes it
L2.append(4)
# Change object pointed to by name L1 -- Lista1
L1[-1] = 10
# Change object pointed to by name L2 -- Lista2
del L2[0]
return L2[:]
Lista1 = [1,2,3]
Lista2 = [1,2,3]
Lista3 = altera(Lista1, Lista2)
print Lista1
print Lista2
print Lista3
然而,L += [2]
有一个棘手的问题,它与L = L + 2
并不完全相同。关于增强赋值语句的Python语言参考部分解释了差异:
像x+=1这样的增广赋值表达式可以重写为x=x+1,以实现类似但不完全相同的效果。在增强版本中,x只计算一次。此外,在可能的情况下,实际操作会就地执行,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。">
函数中发生了两件不同的事情:
def altera(L1, L2):
for elemento in L2:
L1.append(elemento)
# [1] this ^ alters L1 in place
L2 = L2 + [4]
# [2] this ^ creates a new list
L1[-1] = 10
del L2[0]
return L2[:]
为了扩展我在内联中添加的评论:
- 在
altera
中,变量L1
是,无论您传入什么(所以它就是Lista1
(。它不是一个副本,一个具有相同内容的新列表-它指的是相同的实际对象 当你分配
L2 = L2 + [4]
时,你要做两件事:- 创建值为
L2 + [4]
的新列表 - 将
L2
设置为指向这个新列表,而不是您传入的任何列表
如果我们重新命名变量,它将变得显式,并且的工作方式与完全相同:
L3 = L2 + [4] del L3[0] return L3[:]
或者,如果你想修改原始的
L2
(即实际修改Lista2
(,你可以进行L2.append(4) del L2[0] return L2[:]
请注意,最后一行仍然意味着
Lista3
将是与Lista2
不同的列表对象,但它将具有相同的值。如果只使用return L2
,则Lista3
将与L2
完全相同,因此它们将是同一列表对象的两个名称。- 创建值为
如果你想防止这种行为,你可以这样调用altera
:
Lista3 = altera(Lista1[:], Lista2[:])
现在,在altera
中,它将处理自己的参数副本,并且不会影响原始的Lista1
和Lista2
。
使用L2 = L2 + [4]
语句为名称L2
分配新值时,它不再引用Lista2
。您的大多数其他语句都会更改它们已经引用的对象的值。