list类型全局变量函数内修改问题。

下面两个函数:

def func1(x):
    x = list(set(x))
    return len(x)
def func2(x):
    x[:len(x)] = list(set(x))
    return len(x)

-->L = [0,0,1,2,3]
-->func1(L)
4 
-->L
[0,0,1,2,3] # l并未改变

-->func2(L)
4
-->l
[0,1,2,3] # l改变

我知道func2为何会改变L, 但是不知道为何func1不改变L。
望不吝赐教 谢谢!

阅读 3.5k
2 个回答

首先,你需要理解python中【赋值语句】的行为。跟C语言不同,python中的【var=value】读作“把var变量标签分配给value对象”,而不是反过来。

>>> foo=[1,2,3]
>>> bar=foo
>>> id(foo), id(bar)
(2899313114056, 2899313114056)

上述代码可见,两个变量具有相同的内存地址,这在C语言中是不可想象的。
python中的变量就只是个名字,没有自己的地址、类型和值,它只能通过“附着”在【对象】上,临时获得后者的地址、类型和值。

然后,你要理解【foo[index]=value】并非普通的赋值语句,而是在背后调用了foo.__setitem__(index, value)方法。

>>> foo, id(foo)
([1, 2, 3], 2899313114056)
>>> foo[0]=4
>>> foo, id(foo)
([4, 2, 3], 2899313114056)
>>> foo.__setitem__(0, 5)
>>> foo, id(foo)
([5, 2, 3], 2899313114056)

所以,切片赋值语句能够修改列表对象,而普通的赋值语句无法修改列表对象。

赋值操作是产生了一个新的对象,而L原对象并没有发生变化。
切片操作是在原有的对象上进行操作,对L元对象进行了重新赋值。

def func1(x): 
    print(id(x))
    x = list(set(x))
    print(id(x))
    return len(x)

def func2(x):
    print(id(x))
    x[:len(x)] = list(set(x))
    print(id(x))
    return len(x)
   
L = [0,0,1,2,3]

分别调用func1,func2查看L的内存地址

func1赋值 产生了一个新的对象

func1(L)

139912186104520
139912185279368
4
L
[0,0,1,2,3]

func2切片,在原对象上进行修改

func2(L)
139912186104520
139912186104520
4
L
[0, 1, 2, 3]
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题