0

可能重复:
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会保持不变,因为它们是全局变量。

4

4 回答 4

3

列表在 Python 中通过引用传递。Lista1被修改是因为你直接调用.append

for elemento in L2:
    L1.append(elemento)

Lista2未修改,因为您没有修改列表。您使用了加法运算符 ,L2 = L2 + [4]不会修改 L2。相反,它会创建一个新列表并返回结果。

如果您在 Google 上搜索“通过引用传递”一词,您应该能够在 Python 中找到一些很好的解释性示例。

于 2013-01-22T19:18:54.200 回答
0

当您这样做时,L1.append(elemento)您正在调用一个实际更改由变量命名的列表的方法L1L1所有其他设置和值的命令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 只被评估一次。此外,如果可能,实际操作会在原地执行,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。”</p>

于 2013-01-22T19:14:41.997 回答
0

L2当您使用语句为名称分配新值时L2 = L2 + [4],它不再引用Lista2. 您的大多数其他语句都会更改它们已经引用的对象的值。

于 2013-01-22T19:16:25.727 回答
0

您的函数中发生了两种不同的事情:

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[:]

要扩展我添加的内联评论:

  1. 在里面altera,变量L1 你传入的任何东西(所以它 Lista1)。它不是一个副本,一个具有相同内容的新列表——它指的是同一个实际对象
  2. 当你分配L2 = L2 + [4]你做两件事:

    1. 使用值创建一个新列表L2 + [4]
    2. 设置L2为指向这个新列表,而不是你传入的任何内容

    如果我们重命名变量,它会变得显式,并且工作方式完全相同

    L3 = L2 + [4]
    del L3[0]
    return L3[:]
    

    或者,如果您想L2就地修改原件(即实际修改Lista2),您可以这样做

    L2.append(4)
    del L2[0]
    return L2[:]
    

    请注意,最后一行仍然意味着Lista3将是与 不同的列表对象Lista2,但它将具有相同的值。如果您只是return L2Lista3将与相同L2,因此它们将是同一个列表对象的两个名称。

如果你想防止这种行为,你可以altera这样调用:

Lista3 = altera(Lista1[:], Lista2[:])

现在,在里面altera,它将处理自己的参数副本,并且不会影响原始的Lista1and Lista2

于 2013-01-22T19:23:22.617 回答