Python里list的復制問題


寫代碼的時候發現的……太傻了……
查了一下發現里面還有學問,尤其是對列表里嵌套列表要格外注意!

淺拷貝

意思是修改了原列表/復制列表里的值,另一個列表也會被改變。可以理解為它們的內存是同一塊地方?只是給了一個新的指針指向那里。所以無論改哪個,另一個都會被修改。

什么時候會出現淺拷貝?

我可以總結為沒有使用deepcopy()的全是淺拷貝嗎?

  • python里列表list采用“=”賦值的時候
    當修改等號右邊的原list時,新list也會改變。
>>> x = [1,2,3,4]
>>> y = x
>>> y.pop()
4
>>> y
[1, 2, 3]
>>> x
[1, 2, 3]
  • list采用“*”復制多個列表的時候,其實和上面相同,遇到嵌套列表的時候會出問題
>>> A = [[None,None]]
>>> B = A*3
>>> B[0][0]=0
>>> A
[[0, None]]
>>> B
[[0, None], [0, None], [0, None]]
=========== 通過id()查看內存地址
>>> id(B[0])
44594056L
>>> id(B[2])
44594056L
============= 看到A、B里面元素的內存是一樣的!
>>> id(B[2][0])
31897360L
>>> id(B[2][1])
499518584L
>>> id(B[1][0])
31897360L
>>> id(B[1][1])
499518584L
>>> id(A[0][1])
499518584L
>>> id(A[0][0])
31897360L
>>> id(B[0])
44594056L
>>> id(A[0])
44594056L
==============疑問!!!!!! 這個A的地址是啥呀?為啥不是44560456L呢???
>>> id(A)
44595080L
>>> id(B)
44560456L
  • 采用copy()函數
    Python2.7里list沒有這個內置函數,會報錯,但是看到有人用,Python3應該有吧…
>>> z = x.copy()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'copy'

在沒有嵌套的時候,或者字典嵌套列表的時候,copy()是可以復制字典不會被修改的。。那看來是list自己的問題。。

>>> a = {'x':11,'y':22}
>>> a.copy()
{'y': 22, 'x': 11}
>>> b = a.copy()
>>> b.popitem()
('y', 22)
>>> a
{'y': 22, 'x': 11}
>>> b
{'x': 11}
=========================
>>> a = {'x':[11, 22], 'y':[33,44]}
>>> b = a.copy()
>>> a['x']=13
>>> b
{'y': [33, 44], 'x': [11, 22]}
>>> a
{'y': [33, 44], 'x': 13}
>>> a['y']=[33,46]
>>> b
{'y': [33, 44], 'x': [11, 22]}
  • 用for循環生成列表:
old = [1,[1,2,3],3]
new = []
for i in range(len(old)):
    new.append(old[i])
print('Before:')
print(old)
print(new)
new[0] = 3
new[1][0] = 3
print('After:')
print(old)
print(new)

結果:

Before:
[1, [1, 2, 3], 3]
[1, [1, 2, 3], 3]
After:
[3, [3, 2, 3], 3]
[3, [3, 2, 3], 3]
  • 使用切片
old = [1,[1,2,3],3]
new = old[:]
print('Before:')
print(old)
print(new)
new[0] = 3
new[1][0] = 3
print('After:')
print(old)
print(new)

結果:

Before:
[1, [1, 2, 3], 3]
[1, [1, 2, 3], 3]
After:
[3, [3, 2, 3], 3]
[3, [3, 2, 3], 3]

解決方法

采用深復制的方法!

深復制

介紹

就是在內存里新開了一片地方存復制的數據,指針指的是不同的地址。

實現

  • 使用deepcopy()函數,需要引入copy包:
>>> import copy
>>> z = copy.deepcopy(x)
>>> z.pop()
3
>>> z
[1, 2]
>>> x
[1, 2, 3]
import copy
old = [1,[1,2,3],3]
new = copy.deepcopy(old)
print('Before:')
print(old)
print(new)
new[0] = 3
new[1][0] = 3
print('After:')
print(old)
print(new)

結果:

Before:
[1, [1, 2, 3], 3]
[1, [1, 2, 3], 3]
After:
[1, [1, 2, 3], 3]
[3, [3, 2, 3], 3]
  • 解決“*”的使用問題:使用新創建的列表為每個復制的對象賦值
>>> A = [None]
>>> B = [A*2 for i in range(3)]
>>> B
[[None, None], [None, None], [None, None]]
>>> A
[1]
>>> B[0][0]=2
>>> A
[1]
>>> B
[[2, None], [None, None], [None, None]]

注意*和for搭配使用!給我整的有點蒙了……對比下面3個栗子

>>> A[0]=1
>>> B
[[None, None], [None, None], [None, None]]
>>> A
[1]
>>> B[0][0]=1
>>> A
[1]
>>> B[0][0]=2
>>> A
[1]
>>> B  # 明顯看到只修改了B的一個值,A的值並沒有改變。
[[2, None], [None, None], [None, None]]
====================== 這個就是 上面提到過的嵌套列表用for是淺復制呀!
>>> old = [1,[1,2,3],3]
>>> new = [old for i in range(1)]
>>> new
[[1, [1, 2, 3], 3]]
>>> old
[1, [1, 2, 3], 3]
>>> new[0][0] = 3
>>> new
[[3, [1, 2, 3], 3]]
>>> old
[3, [1, 2, 3], 3]
======================== for和“*”一起就變成深復制了?
>>> old = [1,[1,2,3],3]
>>> new = [old for i in range(2)]
>>> new
[[1, [1, 2, 3], 3], [1, [1, 2, 3], 3]]
>>> new[0][0]
1
>>> new[0][0]=3
>>> old
[3, [1, 2, 3], 3]
>>> new = [old*1 for i in range(2)]
>>> new
[[3, [1, 2, 3], 3], [3, [1, 2, 3], 3]]
>>> new[0][0]=1
>>> new
[[1, [1, 2, 3], 3], [3, [1, 2, 3], 3]]
>>> old
[3, [1, 2, 3], 3]

https://www.cnblogs.com/Black-rainbow/p/9577029.html
https://www.cnblogs.com/yinghao-liu/p/8641236.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM