眾所周知,Python是一門面向?qū)ο蟮恼Z言,在Python無論是數(shù)值、字符串、函數(shù)亦或是類型、類,都是對象。

網(wǎng)站制作、成都網(wǎng)站建設(shè)服務團隊是一支充滿著熱情的團隊,執(zhí)著、敏銳、追求更好,是創(chuàng)新互聯(lián)的標準與要求,同時竭誠為客戶提供服務是我們的理念。成都創(chuàng)新互聯(lián)公司把每個網(wǎng)站當做一個產(chǎn)品來開發(fā),精雕細琢,追求一名工匠心中的細致,我們更用心!
對象是在 堆 上分配的結(jié)構(gòu),我們定義的所有變量、函數(shù)等,都存儲于堆內(nèi)存,而變量名、函數(shù)名則是一個存儲于 棧 中、指向堆中具體結(jié)構(gòu)的引用。
要想深入學習Python,首先需要知道Python對象的定義。
我們通常說的Python都是指CPython,底層由C語言實現(xiàn),源碼地址: cpython [GitHub]
Python對象的定義位于 Include/object.h ,是一個名為 PyObject 的結(jié)構(gòu)體:
Python中的所有對象都繼承自PyObejct,PyObject包含一個用于垃圾回收的雙向鏈表,一個引用計數(shù)變量 ob_refcnt 和 一個類型對象指針 ob_type
從PyObejct的注釋中,我們可以看到這樣一句:每個指向 可變大小Python對象 的指針也可以轉(zhuǎn)換為 PyVarObject* (可變大小的Python對象會在下文中解釋)。 PyVarObejct 就是在PyObject的基礎(chǔ)上多了一個 ob_size 字段,用于存儲元素個數(shù):
在PyObject結(jié)構(gòu)中,還有一個類型對象指針 ob_type ,用于表示Python對象是什么類型,定義Python對象類型的是一個 PyTypeObject 接口體
實際定義是位于 Include/cpython/object.h 的 _typeobject :
在這個類型對象中,不僅包含了對象的類型,還包含了如分配內(nèi)存大小、對象標準操作等信息,主要分為:
以Python中的 int類型 為例,int類型對象的定義如下:
從PyObject的定義中我們知道,每個對象的 ob_type 都要指向一個具體的類型對象,比如一個數(shù)值型對象 100 ,它的ob_type會指向 int類型對象PyLong_Type 。
PyTypeObject結(jié)構(gòu)體第一行是一個PyObject_VAR_HEAD宏,查看宏定義可知PyTypeObject是一個變長對象
也就是說,歸根結(jié)底 類型對象也是一個對象 ,也有ob_type屬性,那 PyLong_Type 的 ob_type 是什么呢?
回到PyLong_Type的定義,第一行 PyVarObject_HEAD_INIT(PyType_Type, 0) ,查看對應的宏定義
由以上關(guān)系可以知道, PyVarObject_HEAD_INIT(PyType_Type, 0) = { { _PyObject_EXTRA_INIT 1, PyType_Type } 0} ,將其代入 PyObject_VAR_HEAD ,得到一個變長對象:
這樣看就很明確了,PyLong_Type的類型就是PyType_Typ,同理可知, Python類型對象的類型就是PyType_Type ,而 PyType_Type對象的類型是它本身
從上述內(nèi)容中,我們知道了對象和對象類型的定義,那么根據(jù)定義,對象可以有以下兩種分類
Python對象定義有 PyObject 和 PyVarObject ,因此,根據(jù)對象大小是否可變的區(qū)別,Python對象可以劃分為 可變對象(變長對象) 和 不可變對象(定長對象)
原本的對象a大小并沒有改變,只是s引用的對象改變了。這里的對象a、對象b就是定長對象
可以看到,變量l仍然指向?qū)ο骯,只是對象a的內(nèi)容發(fā)生了改變,數(shù)據(jù)量變大了。這里的對象a就是變長對象
由于存在以上特性,所以使用這兩種對象還會帶來一種區(qū)別:
聲明 s2 = s ,修改s的值: s = 'new string' ,s2的值不會一起改變,因為只是s指向了一個新的對象,s2指向的舊對象的值并沒有發(fā)生改變
聲明 l2 = l ,修改l的值: l.append(6) ,此時l2的值會一起改變,因為l和l2指向的是同一個對象,而該對象的內(nèi)容被l修改了
此外,對于 字符串 對象,Python還有一套內(nèi)存復用機制,如果兩個字符串變量值相同,那它們將共用同一個對象:
對于 數(shù)值型 對象,Python會默認創(chuàng)建0~2 8 以內(nèi)的整數(shù)對象,也就是 0 ~ 256 之間的數(shù)值對象是共用的:
按照Python數(shù)據(jù)類型,對象可分為以下幾類:
Python創(chuàng)建對象有兩種方式,泛型API和和類型相關(guān)的API
這類API通常以 PyObject_xxx 的形式命名,可以應用在任意Python對象上,如:
使用 PyObjecg_New 創(chuàng)建一個數(shù)值型對象:
這類API通常只能作用于一種類型的對象上,如:
使用 PyLong_FromLong 創(chuàng)建一個數(shù)值型對象:
在我們使用Python聲明變量的時候,并不需要為變量指派類型,在給變量賦值的時候,可以賦值任意類型數(shù)據(jù),如:
從Python對象的定義我們已經(jīng)可以知曉造成這個特點的原因了,Python創(chuàng)建對象時,會分配內(nèi)存進行初始化,然后Python內(nèi)部通過 PyObject* 變量來維護這個對象,所以在Python內(nèi)部各函數(shù)直接傳遞的都是一種泛型指針 PyObject* ,這個指針所指向的對象類型是不固定的,只能通過所指對象的 ob_type 屬性動態(tài)進行判斷,而Python正是通過 ob_type 實現(xiàn)了多態(tài)機制
Python在管理維護對象時,通過引用計數(shù)來判斷內(nèi)存中的對象是否需要被銷毀,Python中所有事物都是對象,所有對象都有引用計數(shù) ob_refcnt 。
當一個對象的引用計數(shù)減少到0之后,Python將會釋放該對象所占用的內(nèi)存和系統(tǒng)資源。
但這并不意味著最終一定會釋放內(nèi)存空間,因為頻繁申請釋放內(nèi)存會大大降低Python的執(zhí)行效率,因此Python中采用了內(nèi)存對象池的技術(shù),是的對象釋放的空間會還給內(nèi)存池,而不是直接釋放,后續(xù)需要申請空間時,優(yōu)先從內(nèi)存對象池中獲取。
python的函數(shù)參數(shù)傳遞是"引用傳遞(地址傳遞)"。
python中賦值語句的過程(x = 1):先申請一段內(nèi)存分配給一個整型對象來存儲數(shù)據(jù)1,然后讓變量x去指向這個對象,實際上就是指向這段內(nèi)存(這里有點和C語言中的指針類似)。
在Python中,會為每個層次生成一個符號表,里層能調(diào)用外層中的變量,而外層不能調(diào)用里層中的變量,并且當外層和里層有同名變量時,外層變量會被里層變量屏蔽掉。函數(shù)? 調(diào)用 ?會為函數(shù)局部變量生成一個新的符號表。
局部變量:作用于該函數(shù)內(nèi)部,一旦函數(shù)執(zhí)行完成,該變量就被回收。
全局變量:它是在函數(shù)外部定義的,作用域是整個文件。全局變量可以直接在函數(shù)里面應用,但是如果要在函數(shù)內(nèi)部改變?nèi)肿兞浚仨毷褂胓lobal關(guān)鍵字進行聲明。
注意 :默認值在函數(shù)? 定義 ?作用域被解析
在定義函數(shù)時,就已經(jīng)執(zhí)行力它的局部變量
python中不可變類型是共享內(nèi)存地址的:把相同的兩個不可變類型數(shù)據(jù)賦給兩個不同變量a,b,a,b在內(nèi)存中的地址是一樣的。
首先,Python中一切事物皆對象,變量是對對象在內(nèi)存中的存儲和地址的抽象。所有的變量都可以理解是內(nèi)存中一個對象的“引用”,或者,也可以看似c中void*的感覺。
python中統(tǒng)一都是引用傳遞,同時要注意類型是屬于對象的,而不是變量。而對象有兩種,“可更改”(mutable)與“不可更改”(immutable)對象。在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是可以修改的對象。
當我們寫下面語句時:
Python解釋器其實順序干了兩件事情:
從這里可以看出strings類型是不可變量,不可變實際上指的是不會更該字符串,比如把a = '123' 變?yōu)?a ='1234' 實際上是先創(chuàng)建了 “1234” 再用a去指向它。
但是,像list,dict等“可更改”的變量,他們會直接再本地更改,不會進行副本拷貝。
簡言之,當在 Python 中 a = sth 應該理解為給 sth 貼上了一個標簽 a。當再賦值給 a 的時候,就好象把 a 這個標簽從原來的 sth 上拿下來,貼到其他對象上,建立新的"引用"。
既然Python只允許引用傳遞,那有沒有辦法可以讓兩個變量不再指向同一內(nèi)存地址呢?
copy對于一個復雜對象的子對象并不會完全復制,什么是復雜對象的子對象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是復雜對象的子對象。對于子對象,python會把它當作一個公共鏡像存儲起來,所有對他的復制都被當成一個引用,所以說當其中一個引用將鏡像改變了之后另一個引用使用鏡像的時候鏡像已經(jīng)被改變了。
deepcopy的時候會將復雜對象的每一層復制一個單獨的個體出來。 當然其中主要的操作還是地址問題。
當一個引用傳遞給函數(shù)的時候,函數(shù)自動復制一份引用,這個函數(shù)里的引用和外邊的引用沒有半毛關(guān)系了.所以第一個例子里函數(shù)把引用指向了一個不可變對象,當函數(shù)返回的時候,外面的引用沒半毛感覺.而第二個例子就不一樣了,函數(shù)內(nèi)的引用指向的是可變對象,對它的操作就和定位了指針地址一樣,在內(nèi)存里進行修改.
引用計數(shù)
PyObject是每個對象必有的內(nèi)容,其中ob_refcnt就是做為引用計數(shù)。當一個對象有新的引用時,它的ob_refcnt就會增加,當引用它的對象被刪除,它的ob_refcnt就會減少.引用計數(shù)為0時,該對象生命就結(jié)束了。
優(yōu)點:
缺點:
分享名稱:python傳遞函數(shù)對象 python對象作為參數(shù)傳遞
轉(zhuǎn)載源于:http://chinadenli.net/article18/hijdgp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、外貿(mào)建站、微信小程序、營銷型網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、品牌網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)