参考: https://www.cnblogs.com/zf-blog/p/10613981.html
https://www.cnblogs.com/andywenzhi/p/7453374.html?tdsourcetag=s_pcqq_aiomsg
python 的赋值方式是数据建立内存单元, 将数据存入内存, 然后再将变量名指向存储了数据的内存单元, 如下图示:
不同于 c 的赋值方式: 先为变量分配内存, 然后再将变量的数据存入内存.
为了节省内存, 如果将一个变量的值赋值给另一个变量, 比如, b = 3, a = b,
变量 a 和 b 有完全一致的 ID(指向同一内存地址).
由于上述机制的存在, 实际上没有为变量 a 分配内存, 只是将 a 指向了变量 b 指向的内存地址. 若对此不加注意, 初学者就有可能出现感觉
很 "怪异" 的错误. 比如有两个列表:
- x = [[2, 3]]
- y = [[4, 5], [5, 6], [7, 8], [9, 10]]
期望将 y 列表中的每个元素添加到 x 列表中组成新的列表 z[i], 所有的 z[i] 将组成新的列表:
- z =
- [[[2, 3],[4, 5]],[[2, 3],[5, 6]],[[2, 3],[7, 8]],[[2, 3],[9, 10]]]
如果这样编写程序:
- def list2list(list_a, list_b):
- list_mix, len_e = [], len(list_b)
- for j in range(len_e):
- list_c = list_a
- id(list_c)
- id(list_a)
- print("改变 list_c 赋值之前二者 id:", id(list_c), id(list_a))
- list_c.append(list_b[j])
- id(list_c)
- id(list_a)
- print("改变 list_c 赋值之后二者 id:", id(list_c), id(list_a))
- list_mix.append(list_c)
- return list_mix
- x = [[2, 3]]
- y = [[4, 5], [5, 6], [7, 8], [9, 10]]
- if __name__ == '__main__':
- z = list2list(x, y)
- print(z)
其输出为:
改变 list_c 赋值之前二者 id: 53391968 53391968
改变 list_c 赋值之后二者 id: 53391968 53391968
改变 list_c 赋值之前二者 id: 53391968 53391968
改变 list_c 赋值之后二者 id: 53391968 53391968
改变 list_c 赋值之前二者 id: 53391968 53391968
改变 list_c 赋值之后二者 id: 53391968 53391968
改变 list_c 赋值之前二者 id: 53391968 53391968
改变 list_c 赋值之后二者 id: 53391968 53391968
[[[2, 3], [4, 5], [5, 6], [7, 8], [9, 10]], [[2, 3], [4, 5], [5, 6], [7, 8], [9, 10]], [[2, 3], [4, 5], [5, 6], [7, 8], [9, 10]], [[2, 3], [4, 5], [5, 6], [7, 8], [9, 10]]]
从中可以看出, 无论有没有对列表 list_c 的赋值进行添加更改, 列表 list_c 和 list_a 的 id 都是完全一致的, 这表明二者共用了内存地址. 若对其中一个列表
list_c 的赋值进行更改, 则对应内存地址中的数据将更改, 由于另一列表 list_a 与其共用数据内存, 所以 list_a 的赋值也被 "莫名其妙" 地更改了, 导致输出
结果与预期大相径庭. 关键问题在于列表赋值更改方式 (.append). 可对比下例:
- def add02(a, b):
- len_b = len(b)
- d = []
- for i in range(len_b):
- c = a
- print("c 和 a 赋值更改前的 id:", id(c), id(a))
- c += 1
- print("c 和 a 赋值更改后的 id:", id(c), id(a))
- e = c + b[i]
- d.append(e)
- return d
- x = 5
- y = [6, 7, 8, 9, 10]
- if __name__ == '__main__':
- z = add02(x, y)
- print(z)
输出:
c 和 a 赋值更改前的 id: 259024032 259024032
c 和 a 赋值更改后的 id: 259024048 259024032
c 和 a 赋值更改前的 id: 259024032 259024032
c 和 a 赋值更改后的 id: 259024048 259024032
c 和 a 赋值更改前的 id: 259024032 259024032
c 和 a 赋值更改后的 id: 259024048 259024032
c 和 a 赋值更改前的 id: 259024032 259024032
c 和 a 赋值更改后的 id: 259024048 259024032
c 和 a 赋值更改前的 id: 259024032 259024032
c 和 a 赋值更改后的 id: 259024048 259024032
[12, 13, 14, 15, 16]
可将上文中 list2list() 改为:
- def add_element(a, b):
- c = a + b
- return c
- def list2list(list_b, list_e):
- list_mix, len_e = [], len(list_e)
- list_c = list_b * len_e
- list_mix = list(map(add_element, list_c, list_e))
- return list_mix
- if __name__ == '__main__':
- x = [[[2, 3]]]
- y = [[[4, 5]], [[5, 6]], [[7, 8]], [[9, 10]]]
- route = list2list(x, y)
- print("route:", route)
输出:
来源: http://www.bubuko.com/infodetail-3446899.html