天天看点

python可变元素list在程序中的注意事项1 list的可变性2 扩展总结

1 list的可变性

在python程序中,列表list的存贮方式与int的存贮方式是不同的,换句话说,python中可变类型的存储方式与不可变类型的存储方式是不同的。

例如,对于单一的元素,有如下操作时:

a = 1
b = a
b = 5
print(a, b)
print(id(a),id(b))  # 打印两个变量的地址
           

输出>> 1 5

>> 140731421349024 140731421348896

即对整型变量的赋值相当于一个真正的复制过程,两个变量有了两个不同的内存地址,其实是因为第3句把第二句覆盖掉了。

而对列表元素进行赋值时:

a = [[0,1,2],2,3]
b = a
b[0] = 100
print(a, b)
print(id(a),id(b))  # 打印两个变量的地址
           

输出>> [100, 2, 3] [100, 2, 3]

>> 2847777749608 2847777749608

也就是说列表的赋值本质上是名称多了一个,换句话说,就是列表的名字多了一个,列表还是原来那个列表。两个变量具有相同的内存地址。

下面看一下.copy()方法:

a = [1,2,3]
b = a.copy()
b[0] = 100
print(a, b)
print(id(a),id(b))  # 打印两个变量的地址
           

输出:>> [1, 2, 3] [100, 2, 3]

>> 2744646268360 2744646268744

看起来问题得到了解决,两个变量内存地址也不一样了,然而.cpoy()都叫它浅拷贝,原因在于如下所示:

a = [[0,1,2],2,3]
b = a.copy()
b[0][1] = 100
print(a, b)
print(id(a),id(b))  # 打印两个变量的地址
print(id(a[0]), id(b[0]))  # 打印两个变量中变量的地址
           

输出:>> [[[0, 100, 2], 2, 3] [[0, 100, 2], 2, 3]

>> 2649294660232 2649295880648

>> 2649294660168 2649294660168

可以看到,.copy()方法只是将第一层列表的元素完全拷贝了一份新的内存,再多一层的列表就没有拷贝了,因此称它为浅拷贝。

当列表只有一维时,是可以使用浅拷贝的。

深拷贝:

import copy
a = [[0,1,2],2,3]
b = copy.deepcopy(a)
b[0][1] = 100
print(a, b)
print(id(a),id(b))  # 打印两个变量的地址
print(id(a[0]), id(b[0]))  # 打印两个变量中变量的地址
           

输出:>> [[0, 1, 2], 2, 3] [[0, 100, 2], 2, 3]

>> 2521760495496 2521760589768

>> 2521760495112 2521760547336

深拷贝完全实现了我们想要的拷贝赋值。

2 扩展总结

类似于list有上述特点的还有集合set 、字典dict,即可变元素,因为只有可变元素在赋值后修改之后才可能出现上述问题,不可变元素要不整个元素修改,要不然不改变,不存在上述问题。

赋值语句的本质是为变量多起一个名字,即多一个内存指针,【最大的用处在于变量有了新名字原来的名字就可以删除了】。

类似于赋值语句出现的问题还可能出现在函数传参过程中,把原列表当作函数参数传入函数时,如果函数中列表发生修改,原列表也会跟着修改。