python 列表拷貝的幾種方法

2021-10-04 12:05:56 字數 2811 閱讀 8428

new = old[:]
python老鳥都知道以上**是什麼意思。它複製列表old到new。它對於新手來說是種困惑而且應該避免使用這種方法。不幸的是[:]標記法被廣泛使用,可能是python程式設計師不知道更好的列表複製法吧。

首先我們需要了解python是如何管理物件和變數。python沒有c語言中的變數。在c語言中,變數不止是個名字,它是位元組集合並真實存在於記憶體某個位置上。而在python中,變數僅僅是指向物件的標籤。

看看以下語句:

a = [1, 2, 3]
它表示我們建立了乙個指引指向列表[1, 2, 3],但是a不是列表。如果:

b = a
我們並沒有複製a所指引的列表。我們只是建立了乙個新的標籤b,然後將其指向a所指向的列表。

如果你修改a,那你就同時修改了b,因為它們指向同乙個列表:

>>> a = [1, 2, 3]

>>> b = a

>>> print a

[1, 2, 3, 4]

>>> print b

[1, 2, 3, 4]

內建函式id()可以返回物件的唯一id。該id是物件的記憶體位址。

>>> id(a)

3086056

>>> id(b)

3086056

>>> c = # create a new list

>>> id(c)

2946712

可以看出a和b都指向同乙個記憶體位址。c指向乙個新建的空列表,因此指向了不同的位址。

現在我們要複製a指引的列表。我們必須建立新的列表,然後使用b指引它。

這其實就是 new = old[:]。切片運算子[:]返回乙個序列的切片。切片過程是切下列表的一部分,建立新的列表,將切下的部分複製到新列表。

>>> a[1:3]

[2, 3]

>>> id(a)

3086056

>>> id(a[1:3])

3063400

省略第乙個索引值,切片從列表開始,省略第二個索引值,切片直到列表末端。

>>> a[:3]

[1, 2, 3]

>>> a[1:]

[2, 3, 4]

通過呼叫a[:],我們得到乙個從列表首端開始到末端的切片,也就是a(指引的列表)的完整複製。但這不是複製列表的唯一方式。看看下面這個情況:

>>> b = list(a)

>>> id(a)

3086056

>>> id(b)

3086256

這個是不是看起來更好,少一些隱式,更加pythonic?a[:]看起來有點太像perl。不同於切片標記法,不了解python的人也會明白b是乙個列表。

list()是列表建構函式。它會在傳入的數列基礎上新建乙個列表。數列不一定是列表,它可以是任何型別的數列。

>>> my_tuple = (1, 2, 3)

>>> my_list = list(my_tuple)

>>> print my_list

[1, 2, 3]

>>> id(my_tuple)

3084496

>>> id(my_list)

3086336

而且它還接受生成器。切片筆記法不適用於生成器,因為生成器是不可更改。你不能generator[0],例如:

>>> generator = (x * 3 for x in range(4))

>>> list(generator)

[0, 3, 6, 9]

百分之九十的切片標記法都可以被list()代替。下次你看見[:]的時候試試使用list()替代,這樣可以讓你的**更加可讀。記住,魔鬼藏在細節裡。

附:五種複製方法的比較

>>> import copy

>>> a = [[10], 20]

>>> b = a[:]

>>> c = list(a)

>>> d = a * 1

>>> e = copy.copy(a)

>>> f = copy.deepcopy(a)

>>> print id(a), a

30553152 [[10, 11], 20, 21]

>>> print id(b), b

44969816 [[10, 11], 20]

>>> print id(c), c

44855664 [[10, 11], 20]

>>> print id(d), d

44971832 [[10, 11], 20]

>>> print id(e), e

44833088 [[10, 11], 20]

>>> print id(f), f

44834648 [[10], 20]

從以上可以看出,使用 a[:], list(a), a*1, copy.copy(a)四種方式複製列表結果都可以得到乙個新的列表,但是如果列表中含有列表,所有b, c, d, e四個新列表的子列表都是指引到同乙個物件上。只有使用copy.deepcopy(a)方法得到的新列表f才是包括子列表在內的完全複製。

JS拷貝的幾種方法

淺拷貝 1.對於陣列型別,可以使用slice start,end 方法,返回乙個新的陣列。var arr1 arr.slice 0 備註 slice 方法一直複製到 end 所指定的元素,但是不包括該元素。如果 start 為負,將它作為 length start處理,此處 length 為陣列的長...

深拷貝和淺拷貝的幾種方法

for in 迴圈 var a var b for var k in a 2.object.assgin 與 號區別在於,修改了a.name就會變化,而這個不會變,但是這個到下面一層也會變化!就是說等號只進行了一層深拷貝。var a var b object.assign a 如果b原來是有屬性的物...

python 列表去重 陣列 的幾種方法

一 方法1 如下 複製 思路看起來比較清晰簡單 也可以保持之前的排列順序。二 方法2 通過set方法進行處理 如下 複製 ids 1,4,3,3,4,2,3,4,5,6,1 ids list set ids 處理起來比較簡單,使用了集合方法set進行處理,不過結果不會保留之前的順序。三 方法3 利用...