循环中的python列表变异,全局修改与本地修改

时间:2015-07-13 21:45:45

标签: list python-2.7 loops scope

Halp,也许比我在Python上更有经验的人可以回答这个(noobish)问题。

我无法弄清楚为什么列表会发生以下行为。

让我们拥有以下功能:

def foo1(L):
   """
    L is a list
   """
   L = ['new', 'stuff']
   print L

def foo2(L):
   """
    L is a list
   """
   L[:] = ['new', 'stuff']
   print L

IDLE输出以下内容:

>>>L = [1,2,3]  
>>>foo1(L)  
['new', 'stuff']  
>>>L  
[1,2,3]  

>>>foo2(L)  
['new', 'stuff']  
>>>L  
['new', 'stuff']

我无法弄清楚为什么第一个函数只是临时修改列表,但第二个函数全局修改列表。我不认为这是一个范围问题,而是L =与L [:] =

的问题

我知道如果我使用列表推导来改变L或使用类似L.append()或其他方法来改变函数中的L,那么它也会全局修改L.

我不是Python的新手,但是,通常情况下,我只是在编码时解决我的问题,如果它有效,我不会质疑它。我今年夏天花时间学习最佳实践,并掌握蟒蛇的习惯。

编辑: 所以Martijn决定将这个问题标记为重复,但我不同意。链接的问题没有解决我的问题。

当一个变量传递给一个函数时,该函数会创建一个具有自己范围的新环境。此环境中的变量仅存在于该环境的范围内,而不存在于其他任何地方。因此,当我的列表L被传递给foo1和foo2时,临时列表L仅在该函数调用的范围内。换句话说,在调用foo1(L)之前,存在名为L的列表,其等于[1,2,3]。在调用foo1(L)之后,创建了一个新的函数环境,它包含一个临时列表,也称为L,它只存在于该函数的范围内。如果我在函数中通过L = [blah,blah,blah]修改L,则原始列表L没有任何反应。但是,通过在函数内使用L上的[:],现在修改了原始列表。为什么?在创建一个范围有限的临时变量之后,python如何知道它需要修改具有全局范围的原始变量?这个概念对我来说没有意义。

1 个答案:

答案 0 :(得分:0)

参数L和全局变量L都指向内存中的相同对象。当你传递对象时,它只是对全局对象的引用,因为这是引用和赋值在python中的工作方式。 因此,当您在['new', 'stuff']中执行foo1时,将值分配给L本地副本,即参数,因为这是对分配的第一次查找。 但是在L[:] = ['new', 'stuff']中执行foo2时,您正在做一个影响全局变量的切片。

您可以通过检查全局和参数L的ID是否相同来对此进行测试。

L = [1, 2, 3]

B = L

id(B) == id(L)    # True

def foo(L):
   print(id(L) == id(B))

foo(L)    # TRUE

# or..

def foobar(L):
    print(id(locals()['L']) == id(globals()['L']))

希望这会有所帮助。 :)