局部和全局变量之间的区别?

时间:2013-01-22 19:10:47

标签: python variables global local

  

可能重复:
  Python passing list as argument

我找了很多关于这方面的话题,但我无法理解真正发生的事情。

我有这段代码:

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没有被修改。但是在测试代码之前,我认为Lista1Lista2将保持不变,因为它们是全局变量。

4 个答案:

答案 0 :(得分:3)

列表在Python中通过引用传递。 Lista1已修改,因为您直接致电.append

for elemento in L2:
    L1.append(elemento)
未修改

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

如果谷歌使用术语“通过引用传递”,你应该能够在Python中找到一些很好的解释性示例。

答案 1 :(得分:0)

执行L1.append(elemento)时,您正在调用实际更改变量L1命名的列表的方法。设置L1L2值的所有其他命令实际上只是为新变量创建新名称。

此版本不会改变任何内容:

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 Language Reference部分解释了差异:

  

像x + = 1这样的增强赋值表达式可以重写为x = x + 1,以实现类似但不完全相同的效果。在增强版本中,x仅评估一次。此外,在可能的情况下,实际操作是就地执行的,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。“

答案 2 :(得分:0)

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

答案 3 :(得分: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. 创建一个新列表
    3. L2设置为指向此新列表,而不是您传入的任何内容
    4. 如果我们重新命名变量,它变得明确,并且完全相同:

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

      或者,如果您想要修改原始L2(即实际修改Lista2),您可以

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

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

      < / LI>

      如果您想阻止此行为,可以像这样致电L2

      altera

      现在,在Lista3 = altera(Lista1[:], Lista2[:]) 内,它将处理自己的参数副本,并且不会影响原始alteraLista1