python中賦值引用 淺拷貝 深拷貝

2021-08-22 15:03:32 字數 3123 閱讀 1982

t=[1,2,2]

defmain

(n):

n[0]=3

return n

main(t)

print(t)

'輸出是t[3,2,2]'

同樣,使用return的返回值也是一樣的結果,因為無論怎麼說,在python中的賦值都是引用,變數本身就是乙個標籤,只是我們可以通過變數取訪問記憶體中的資料而已。

在實際的使用過程中如果需要複製乙個變數,使用copy模組,這就涉及到copy模組的深拷貝和淺拷貝問題:

對於list,可以使用

b=[1,2,2]

a=b[:]

需要注意的一點

對於可變物件和不可變物件,都是淺拷貝,但是對於不可變物件(字串和tupple),如果物件發生了修改,則會開闢新的儲存空間來儲存這個變數,如果乙個物件中既有可變物件,又有不可變物件,則是分別用他們自己的準則來決定是不是要開闢空間。

淺拷貝就是在使用copy.copy來開闢記憶體空間的時候出現的

比如如果是直接賦值

a=['asd',[1,2,3]]

b=ab[0]='asds'

輸出a和b的結果是:

['asds', [1, 2, 3, 4]]

['asds', [1, 2, 3, 4]]

被拷貝物件和拷貝物件的值都發生了更改,如果我們使用copy.copy()來進行淺拷貝,比如:

a=['asd',[1

,2,3]]

b=copy.copy(a)

b[0]='asds'

(4)

輸出a和b的結果是:

['asd', [1, 2, 3, 4]]

['asds', [1, 2, 3, 4]]

所以說淺拷貝的本質也只是在其他記憶體上開了個小空間來儲存對原來物件的引用,如果新拷貝的物件的值發生了更改,那個會判斷這個是不是可變物件,如果是可變物件,那麼被拷貝物件和拷貝物件的值都發生改變,如果是不可變物件,則開闢新的空間來儲存。

深拷貝當然就不用說了,就是開記憶體儲存被拷貝物件的所有資訊!

a=['asd',[1

,2,3]]

b=copy.copy(a)

b[0]='asds'

(4)

輸出的a和b的結果是:

['asd', [1, 2, 3]]

['asds', [1, 2, 3, 4]]

def

func_int

(a):

a += 4

deffunc_list

(a_list):

a_list[0] = 4

t = 0

func_int(t)

print t

# output: 0

t_list = [1, 2, 3]

func_list(t_list)

print t_list

# output: [4, 2, 3]

對於上面的輸出,不少python初學者都比較疑惑:第乙個例子看起來像是傳值,而第二個例子確實傳引用。其實,解釋這個問題也非常容易,主要是因為可變物件和不可變物件的原因:對於可變物件,物件的操作不會重建物件,而對於不可變物件,每一次操作就重建新的物件。

在函式引數傳遞的時候,python其實就是把引數裡傳入的變數對應的物件的引用依次賦值給對應的函式內部變數。參照上面的例子來說明更容易理解,func_int中的區域性變數」a」其實是全部變數」t」所指向物件的另乙個引用,由於整數物件是不可變的,所以當func_int對變數」a」進行修改的時候,實際上是將區域性變數」a」指向到了整數物件」1」。所以很明顯,func_list修改的是乙個可變的物件,區域性變數」a」和全域性變數」t_list」指向的還是同乙個物件。

為什麼修改字典d的值不用global關鍵字先宣告呢?

s = 'foo'

d =

deff

(): s = 'bar'

d['b'] = 2

f()print s # foo

print d #

這是因為,在s = 『bar』這句中,它是「有歧義的「,因為它既可以是表示引用全域性變數s,也可以是建立乙個新的區域性變數,所以在python中,預設它的行為是建立區域性變數,除非顯式宣告global,global定義的本地變數會變成其對應全域性變數的乙個別名,即是同乙個變數。

在d[『b』]=2這句中,它是「明確的」,因為如果把d當作是區域性變數的話,它會報keyerror,所以它只能是引用全域性的d,故不需要多此一舉顯式宣告global。

上面這兩句賦值語句其實是不同的行為,乙個是rebinding(不可變物件), 乙個是mutation(可變物件).

但是如果是這樣

d = 

deff

(): d = {}

d['b'] = 2

f()print d #

list_a = 

defa

(): list_a = [1] ## 語句1

a()print list_a #

list_b =

defb

():b()

print list_b # [1]

陷阱2

不要再引數中指明是list

in[2]: def foo(a, b, c=):

... print(c)

...in[3]: foo(1, 1)

[1, 1]

in[4]: foo(1, 1)

[1, 1, 1, 1]

in[5]: foo(1, 1)

[1, 1, 1, 1, 1, 1]

相關鏈結

引用和賦值

**深拷貝和淺拷貝

關於引用和賦值以及拷貝作用域等等,很詳細

深拷貝和淺拷貝

Python中的賦值引用 淺拷貝 深拷貝小結

有部分參考資料 from copy import copy,deepcopy l 1,2,3,4,1,2,3 new l l copy l copy l deepcopy l deepcopy l print l id l print new l id new l print copy l id c...

Python 賦值 淺拷貝 深拷貝

賦值 a b,只拷貝了物件的引用,沒有拷貝內容。兩個物件的id一樣 淺拷貝 copy.copy 構造乙個新的復合物件,然後將子物件引用插入到原始物件的副本中。深拷貝 copy.deepcopy 構造乙個新的復合物件,然後遞迴地將子物件副本插入原始物件的副本。給個栗子 從這個栗子可以看出,對c進行修改...

python賦值 淺拷貝 深拷貝

視覺化 首先了解知識點 可變 list,dict 和不可變 string,int,tuple 淺拷貝 對於string int來說沒有意義,因為它們資料就一層,對於tuple由於是不可變型別所以新的物件會指向原來的物件位址,對於list和dict,新的物件會在記憶體中開闢乙個新的記憶體空間,並且只拷...