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如何知道它需要修改具有全局范围的原始变量?这个概念对我来说没有意义。
答案 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']))
希望这会有所帮助。 :)