你想複制一個對象.因為在Python中,無論你把對象做為參數傳遞,做為函數傳回值,都是引用傳遞的.
讨論:
标準庫中的copy子產品提供了兩個方法來實作拷貝.一個方法是copy,它傳回和參數包含内容一樣的對象.
import copy
new_list = copy.copy(existing_list)
有些時候,你希望對象中的屬性也被複制,可以使用deepcopy方法:
import copy
new_list_of_dicts = copy.deepcopy(existing_list_of_dicts)
當你對一個對象指派的時候(做為參數傳遞,或者做為傳回值),Python和Java一樣,總是傳遞原始對象的引用,而不是一個副本.其它一些語言當指派的時候總是傳遞副本.Python從不猜測使用者的需求 ,如果你想要一個副本,你必須顯式的要求.
Python的行為很簡單,迅速,而且一緻.然而,如果你需要一個對象拷貝而并沒有顯式的寫出來,會出現問題的,比如:
>>> a = [1, 2, 3]>>> b = a>>> b.append(5)>>> print a, b [1, 2, 3, 5] [1, 2, 3, 5]
在這裡,變量a和b都指向同一個對象(一個清單),是以,一旦你修改了二者之一,另外一個也會受到影響.無論怎樣,都會修改原來的對象.
注意:
要想成為一個Python高手,首先要注意的問題就是對象的變更操作和指派,它們都是針對對象的引用操作的.一個語句比如a = []将a重新綁定給一個新對象,但不會影響以前的對象.然而,對象複制卻不同,當對象複制後,對象變更操作就有了差別.
如果你想修改一個對象,而且想讓原始的對象不受影響,那你就需要對象複制.正如本節說的一樣,你可以使用copy子產品中的兩個方法來實作需求.一般的,可以使用copy.copy,它可以進行對象的淺複制(shallow copy),它複制了對象,但對于對象中的元素,依然使用引用.
淺複制,有時無法獲得一個和原來對象完全一緻的副本,如果你想修改對象中的元素,不僅僅是對象本身的話:
>>> list_of_lists = [ ['a'], [1, 2], ['z', 23] ]
>>> copy_lol = copy.copy(lists_of_lists)
>>> copy_lol[1].append('boo')
>>> print list_of_lists, copy_lol
[['a'], [1, 2, 'boo'], ['z', 23]] [['a'], [1, 2, 'boo'], ['z', 23]]
在這裡,變量list_of_lists,copy_lol指向了兩個不同的對象,是以我們可以修改它們任何一個, 而不影響另外一個.然而,如果我們修改了一個對象中的元素,那麼另一個也會受影響,因為它們中的元素還是共享引用.
如果你希望複制一個容器對象,以及它裡面的所有元素(包含元素的子元素),使用copy.deepcopy,這個方法會消耗一些時間和空間,不過,如果你需要完全複制,這是唯一的方法.
對于一般的淺拷貝,使用copy.copy就可以了,當然,你需要了解你要拷貝的對象.要複制清單L,使用list(L),要複制一個字典d,使用 dict(d),要複制一個集合s,使用set(s),這樣,我們總結出一個規律,如果你要複制一個對象o,它屬于内建的類型t,那麼你可以使用t(o) 來獲得一個拷貝.dict也提供了一個複制版本,dict.copy,這個和dict(d)是一樣,我推薦你使用後者,這個使得代碼更一緻,而且還少幾個字元.
要複制一個别的類型,無論是你自己寫的還是使用庫中的,使用copy.copy,如果你自己寫一個類,沒有必要費神去寫clone和copy函數,如果你想定義自己的類複制的方式,實作一個__copy__,或者__getstate__和__setstate__.如果你想定義自己類型的 deepcopy,實作方法__deepcopy__.
注意你不用複制不可修改對象(string,數字,元組),因為你不用擔心修改它們.如果你想嘗試一下複制,依然會得到原來的.雖然無傷大雅,不過真的浪費盡力:
>>> s = 'cat'
>>> t = copy.copy(s)
>>> s is t
True
is操作符用于不僅判斷兩個對象是否完全一緻,而且是同一個對象(is判斷辨別符,要比較内容,使用==),判斷辨別符是否相等對于不可修改對象沒有什麼意義.然而 ,判斷辨別符對于可修改對象有時候是很重要的,比如,你不确定a和b是否指向同一個對象,使用a is b會立刻得到結果.這樣你可以自己判斷是否需要使用對象拷貝.
注意:
你可以使用另一種拷貝方式,給定一個清單L,無論是完整切片L[:]或者清單解析[x for x in L],都會獲得L的淺拷貝,試試L+[],L*1...但是上面兩種方法都會使人迷惑,使用list(L)最清晰和快速,當然,由于曆史原因,你可能會經常看到L[:]的寫法.
對于dict,你可能見過下面的複制方法:
>>> for somekey in d:
... d1[somekey] = d[somekey]
或者更簡單一些的方法,d1={},d1.update(d),無論怎樣,這些代碼都是缺乏效率的,使用d1=dict(d)吧.
相關說明:
copy(x)
Shallow copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
deepcopy(x, memo=None, _nil=[])
Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.