Python的物件傳遞與Copy函式使用詳解

2022-09-27 10:21:08 字數 4695 閱讀 5556

1、物件引用的傳值或者傳引用

python中的物件賦值實際上是簡單的物件引用。也就是說,當你建立乙個物件,然後把它賦值給另乙個變數的時候,python並沒有拷貝這個物件,而是拷貝了這個物件的引用。這種方式相當於值傳遞和引用傳遞的一種綜合。如果函式收到的是乙個可變物件(比如字典或者列表)的引用,就能修改物件的原始值--相當於通過「引用傳遞」來賦值。如果函式收到的是乙個不可變變數(比如數字、字串或者元祖)的引用,就不能直接修改原始物件--相當於通過「值傳遞」來賦值。

先看乙個數字傳遞的例子:

>>> def test(a):

... print id(a)

... a = a + 1

... print id(a)

... return a

...>>> b =19

>>> id(b)

38896272

>>> c = test(b)

38896272

38896260

>>> id(b)

38896272

>>> b

19id函式可以獲得物件的記憶體位址.

很明顯從上面例子可以看出,將b變數作為引數傳遞給了test函式,傳遞了b的乙個引用,把b的位址傳遞過去了,所以在函式內獲取的變數a的位址跟變數b的位址是一樣的,但是在函式內,對a進行賦值運算,a的值從19變成了20,實際上19和20所佔的記憶體空間都還是存在的,賦值運算後,a指向20所在的記憶體。而b仍然指向19所在的記憶體,所以後面列印b,其值還是19.

另外,關於整數變數的id,所有在[-5,256]範圍內的整數,python是提前分配好空間放在陣列裡初始化好的,所以兩個變數如果是相同的小整數,物件都是最開始初始化的那乙個,所以兩個變數的id是一樣的。

所有在[-5,256]範圍外的整數的話,每次都會新建乙個的,所以id會改變

>>> a = 256

>>> id(a)

43340980

>>> b = 256

>>> id(b)

43340980 # a和b的id相同

>>> a = 257

>>> id(a)

44621040

>>> b = 257

>>> id(b)

44620908 # a和b的id不同

>>> a = -5

>>> id(a)

43338160

>>> b = -5

>>> id(b)

43338160

>>> a = -6

>>> id(a)

44621184

>>> b = -6

>>> id(b)

44621112

再看乙個列表傳遞的例子:

>>> def test(a):

... print id(a)

... a[0] = 100

... print id(a)

... return a

...>>> b = [7,8,9,10]

>>> id(b)

46408088

>>> c = test(b)

46408088

46408088

>>> id(b)

46408088

>>> b

[100, 8, 9, 10]

從上面例子可以看出,將b變數作為引數傳遞給了test函式,傳遞了b的乙個引用,把b的位址傳遞過去了,所以在函式內獲取的變數a的位址跟變數b的位址是一樣的,但是在函式內,對a進行賦值運算,a[0]的值ldhclirlbh從7變成了100,但是a的id並沒有發生變化,還是和變ldhclirlbh量b的位址是一樣的,所以後面列印b,b[0]的值也從7變成了100.

2、關於可變變數和不可變變數:

這裡的可變不可變,是指記憶體中的那塊內容(value)是否可以被改變

不可變變數:

number: int, float, str, 元組。--指它的部分(比如element,attribute不能改變)不能改變;並不是整體不可變。另外,py程式設計客棧thon所有變數皆物件。int也是乙個物件。

>>> a = 10000

>>> id(a)

46573412

>>> a = 10000000

>>> id(a)

46573460 #數字變數重新賦值後,id發生了變化

>>> s = 'abc'

>>> s[1] = d #字串變數中的某乙個元素不能進行改變

traceback (most recent call last):

file "", line 1, in

typeerror: 'str' object does not support item assignment

>>> id(s)

39103328

>>> s = 'ttt'

>>> id(s) #字串變數進行重新賦值後,id發生了變化

46425368

從上面的例子中可以看出,數字變數、字元變數在重新賦值後,id都會發生變化,這是因為不可變變數的賦值是通過在記憶體中新申請一塊區域,把新的值儲存到該區域,然後改變不可變變數的引用,指向新的記憶體區域,從而改變了不可變變數的值。

可變變數

class, class instance;列表,dict,

例1.可變變數中元素的賦值

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

>>> id(list)

45486568

>>> for i in list:

... print id(i)

40207208

40207196

40207184

>>> list[0] = 0

>>> id(list)

45486568 # 變數的id並沒有發生改變

>>> for i in list:

... print id(i)

40207220 # 該元素的id發生了改變

40207196

40207184

例2.可變變數的賦值

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

>>> id(list)

43783392

>>> list =[2,3,5]

>>> id(list) # 該變數的id發生了改變

44454296

從上面的例子可以看出,列表中的元素重新賦值,整個列表的id不會發生改變,但是該元素的id會發生該生。因為列表中儲存的其實是對各個元素的引用,所以對該元素賦值的結果就是元素的引用發生了改變。

總之,無論是可變變數還是不可變變數,只要對整個變數進行賦值,python都在記憶體中新申請一塊區域,把新的值儲存到該區域,然後改變不可變變數的引用,指向新的記憶體區域;如果可變變數中的元素進行賦值,支隊導致該元素的變化,不會導致父物件的變化。

3、 深拷貝 vs 淺拷貝

copy.copy() 淺拷貝

copy.deepcopy() 深拷貝

淺拷貝是新建立了乙個跟原物件一樣的型別,但是其內容是對原物件元素的引用。這個拷貝的物件本身是新的,但內容不是。如果原物件的元素包含不是基本資料結構,而是list、dict或者物件的話,那麼原物件或者拷貝物件改變list、dict或者物件裡面的內容的話,會導致二者同時發生改變。

深拷貝則是對原物件的完全拷貝,包含物件裡面的子物件的拷貝,因此拷貝物件和原物件二者是完全獨立,任何一方的改變對另外一方都不會產生任何的影響。

>>> import copy

>>> list = [1, 2, [3, 4]]

>>> copy_list = copy.copy(list)

>>> deepcopy_list = copy.deepcopy(list)

>>>

>>> id(list)

44454296

>>> id(copy_list)

44515736

>>> id(deepcopy_list)

44455736

>>>

>>> for k in list:

... print id(k)

43338088 43338076 44430120

>>> for k in c程式設計客棧opy_list:

... print id(k)

43338088 43338076 44430120 # copy物件的內容和原物件完全一樣

>>> for k in deepcopy_list:

... print id(k)

43338088 43338076 44457456 # deepcopy物件的內容和原物件有區別:列表元素的id不一樣;數字元素id一樣,原因是所有相同數字的變數的引用都是一樣的。

>>>

>>> list[2][0] = 30

>>> list

[1, 2, [30, 4]]

>>> copy_list

[1, 2, [30, 4]] # 原物件的子物件中的元素發生改變後,會導致copy物件發生同樣的改變

>>> deepcopy_list

[1, 2, [3, 4]] #原物件的子物件中的元素發生改變後,不會導致deepcopy物件發生同樣的改變

本文標題: python的物件傳遞與copy函式使用詳解

本文位址: /jiaoben/python/295644.html

json物件與C 物件傳遞

c 物件不能直接傳遞js js物件不能直接傳遞給c 可以使用序列化當做中間層來進行傳遞物件 序列化 在中間將格式轉換進行傳遞,中間物件可以跨語言,c 能認識,js也能認識,這種資料格式。比如 json,xml 原理如圖 步驟 在c 裡引入序列化的命名空間 例項化序列化的類 把c 物件序列化成json...

JSF心得 JAVA的物件傳遞是引用傳遞

基於jsf component的portlet的構建通常需要了解一下幾點 1.所有的jsf component都是單一例項的,也就是說在每乙個session週期內,乙個ui元件只存在乙個例項 2 對於ui元件中的變數,對於不屬於ui元件的物件 ftpclient 在ui物件構建初期通過建構函式傳遞,...

JSF心得 JAVA的物件傳遞是引用傳遞

基於jsf component的portlet的構建通常需要了解一下幾點 1.所有的jsf component都是單一例項的,也就是說在每乙個session週期內,乙個ui元件只存在乙個例項 2 對於ui元件中的變數,對於不屬於ui元件的物件 ftpclient 在ui物件構建初期通過建構函式傳遞,...