Python 類,對象,數(shù)據(jù)分類,函數(shù)參數(shù)傳遞詳解
最近在基于python寫的接口自動化腳本,從Excel表中讀取所有數(shù)據(jù),每一行數(shù)據(jù)保存為字典,再將很多行的字典數(shù)據(jù)保存到一個列表里,運(yùn)行時發(fā)現(xiàn),列表中的字典均相同,且一直是excel最后一行的數(shù)據(jù),情況類比如下:
dd = {"a":1,"b":10} i = 2 list1 = [] while i< 5: dd["a"] = i i+=1 list1.append(dd) print("list1:{}".format(list1))
運(yùn)行結(jié)果如下圖,打印結(jié)果并不是預(yù)期的 list1:[{'b': 10, 'a': 2}, {'b': 10, 'a': 3}, {'b': 10, 'a': 4}] ,為什么呢??
問題的關(guān)鍵在于,數(shù)據(jù)分為可變及不可變類型,python中字典是可變類型,列表實際保存的是字典所指向的那片內(nèi)存,而這片內(nèi)存的內(nèi)容,保存的是最后一次修改的值?! ?/p>
為加深理解,重新溫故下python關(guān)于類、對象、數(shù)據(jù)分類、函數(shù)傳遞參數(shù)的相關(guān)知識。
1、基本概念
1.1 類與對象的關(guān)系
對象:包含屬性(特征)和方法(行為)。例如,狗作為一個對象,有年齡、眼睛等特征,有走路、覓食等行為。
類:即把有相同屬性和方法的對象進(jìn)行提?。ǔ橄蠡菍ο蟮哪0?。例如,對狗這個對象進(jìn)行抽象化,把具有覓食行為,具有年齡等相同特征的對象,抽象一個Animal類。1.2 self的作用
class Animal(): self.age = 0 #類屬性 def Eat(self): #類方法 print ("覓食") dog = Animal() #類的實例化,即對象 cat = Animal() #類的實例化,即對象 dog.Eat() #相當(dāng)于Animal.Eat(dog)
在python里,當(dāng)對象調(diào)用類中的方法時,需要先把對象作為參數(shù)傳入方法中,相當(dāng)于告訴類,“老子來調(diào)用這個方法啦,留個名”。而對象把自己傳入方法,就是通過self?! ?/p>
如上圖,dog對象調(diào)用Eat(self)方法,執(zhí)行dog.Eat()時,先用self接收dog對象,等同于執(zhí)行Animal.Eat(dog)?! ?/p>
正是因為self參數(shù)接收的是對象本身,而self的英文翻譯就是“自己,自個”,所以大家都約定俗成的用了這個單詞,它并不是python的關(guān)鍵字,如果換成把self緩存that,here等,其實也一樣。
1.3 對象的創(chuàng)建與引用
在python中,一切都是對象。對象均具備三個屬性:地址,類型,值。
當(dāng)"左邊 = 右邊"時,實際是創(chuàng)建、引用對象的過程?! ?/p>
如a = 3, 3實際上是一個對象,且對象的值為3,對象創(chuàng)建后存儲在內(nèi)存中,被a所引用。
如果對象中的值可以更改,該值屬于可變類型;
如果對象中的值不能更改,該值屬于不可變類型;
如果對象中又包含對其他對象的引用,該對象就是容器,如d={},list1[0]=d,list1就是容器。
2、數(shù)據(jù)的分類
數(shù)據(jù)可變不可變,指的是存儲在內(nèi)存的內(nèi)容,即對象的值,是否可以被修改,分為倆大類:
- 不可變類型:例如整型,浮點型,字符串類型;
- 可變類型:例如字典,列表。
2.1 不可變類型
不可變類型,即對象本身的值不可以改變?! ?/p>
python在引用不可變類型的對象時,會尋找該對象是否創(chuàng)建過,若該對象已創(chuàng)建,則變量會直接引用該對象,不會再申請新的內(nèi)存空間。
a = 3 b = 3 print(id(a)) print(id(b)) a = 4 print(id(a)) >> 502853488 >> 502853488 >> 502853520
3這個對象創(chuàng)建后,a、b都引用了它,所以打印出來的地址是相同的?! ?/p>
當(dāng)a = 4后,因為3屬于不可變類型,因此又創(chuàng)建了一個4的對象,將a指向這個新創(chuàng)建的對象。
2.2 可變類型
可變類型,即在對象本身的值允許改變,而內(nèi)存地址不需要改變,如 列表.append。
python在引用不可變類型的對象時,會先申請新的內(nèi)存空間,來存儲這個對象,有別于不可變類型。
a = [1,2,3] b = [1,2,3] print(id(a)) print(id(b)) a.append(4) print(id(a)) >> 48751048 >> 48751560 >> 48751048
a、b創(chuàng)建了倆個相同內(nèi)容的列表,但是其指向的內(nèi)存地址不相同。當(dāng)對a指向的可變對象增加元素后,a所引用的對象內(nèi)容已改變,但地址依舊不變。
3、函數(shù)傳遞參數(shù)的方式
3.1 值傳遞
主函數(shù)向調(diào)用函數(shù)傳遞的參數(shù)是不可變類型時,實際上只是將實參的拷貝(即臨時副本)傳遞給了被調(diào)用函數(shù),并不是實參本身,這樣被調(diào)函數(shù)不能直接修改主調(diào)函數(shù)中變量的值,而只能修改其私有的臨時副本的值。
def ChangeList(list1): list1[1] = 5 li = [1,1,1] print (li) ChangeList(li) print (li) >> [1, 1, 1] >> [1, 5, 1]
如代碼所示,s是字符串,屬于不可變類型,傳遞給ChangeString(s)時,是將s實際的值傳入,s本身不會被改變。
3.2 引用傳遞
主函數(shù)向調(diào)用函數(shù)傳遞的參數(shù)是可變類型時,實際上是將實參的引用傳入了調(diào)用函數(shù),對引用的操作等于對其指定的對象進(jìn)行操作。
def ChangeList(list1): list1[1] = 5li = [1,1,1] print (li) ChangeList(li) print (li) >> [1, 1, 1] >> [1, 5, 1]
如代碼所示,li是列表,屬于可變類型,傳遞給ChangeList(list1)時,list1也指向了li所引用的同一片內(nèi)存。
總結(jié)
1、類是對象的抽象化,對象是類的實例化,在python中一切都是對象?! ?/p>
2、self代表的是對象本身,將對象作為一個參數(shù)傳入方法中執(zhí)行?! ?/p>
3、內(nèi)存中的內(nèi)容按是否可以修改,分為可變類型和不可變類型,所對應(yīng)的可變對象和不可變對象,創(chuàng)建和引用方式也不同?! ?/p>
4、不可變類型參數(shù)被函數(shù)調(diào)用時,是值傳遞,可變類型參數(shù)被函數(shù)調(diào)用時,是引用傳遞。
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
python連接sql?server數(shù)據(jù)庫的方法實戰(zhàn)
當(dāng)我們用Python來編寫網(wǎng)站,必須要能夠通過python操作數(shù)據(jù)庫,下面這篇文章主要給大家介紹了關(guān)于python連接sql?server數(shù)據(jù)庫的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08python tkinter實現(xiàn)界面切換的示例代碼
今天小編就為大家分享一篇python tkinter實現(xiàn)界面切換的示例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06淺談python數(shù)據(jù)結(jié)構(gòu)之動態(tài)規(guī)劃
這篇文章主要介紹了淺談python數(shù)據(jù)結(jié)構(gòu)之動態(tài)規(guī)劃,可能很多小伙伴會覺得這個詞很陌生,覺得這是一種很復(fù)雜的思想,學(xué)習(xí)起來很困難,其實并不是這樣,動態(tài)規(guī)劃所講述的知識與動態(tài)與規(guī)劃并無太大關(guān)聯(lián),需要的朋友可以參考下2023-07-07詳細(xì)聊聊為什么Python中0.2+0.1不等于0.3
最近在學(xué)習(xí)過程中發(fā)現(xiàn)在計算機(jī)JS時發(fā)現(xiàn)了一個非常有意思事,0.1+0.2的結(jié)果不是0.3,而是0.30000000000000004,下面這篇文章主要給大家介紹了關(guān)于為什么Python中0.2+0.1不等于0.3的相關(guān)資料,需要的朋友可以參考下2022-12-12