成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

python的函數(shù)存在堆,Python堆

Python對(duì)象

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

創(chuàng)新互聯(lián)專注于企業(yè)成都全網(wǎng)營(yíng)銷、網(wǎng)站重做改版、個(gè)舊網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、html5、商城開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為個(gè)舊等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

對(duì)象是在 堆 上分配的結(jié)構(gòu),我們定義的所有變量、函數(shù)等,都存儲(chǔ)于堆內(nèi)存,而變量名、函數(shù)名則是一個(gè)存儲(chǔ)于 棧 中、指向堆中具體結(jié)構(gòu)的引用。

要想深入學(xué)習(xí)Python,首先需要知道Python對(duì)象的定義。

我們通常說的Python都是指CPython,底層由C語(yǔ)言實(shí)現(xiàn),源碼地址: cpython [GitHub]

Python對(duì)象的定義位于 Include/object.h ,是一個(gè)名為 PyObject 的結(jié)構(gòu)體:

Python中的所有對(duì)象都繼承自PyObejct,PyObject包含一個(gè)用于垃圾回收的雙向鏈表,一個(gè)引用計(jì)數(shù)變量 ob_refcnt 和 一個(gè)類型對(duì)象指針 ob_type

從PyObejct的注釋中,我們可以看到這樣一句:每個(gè)指向 可變大小Python對(duì)象 的指針也可以轉(zhuǎn)換為 PyVarObject* (可變大小的Python對(duì)象會(huì)在下文中解釋)。 PyVarObejct 就是在PyObject的基礎(chǔ)上多了一個(gè) ob_size 字段,用于存儲(chǔ)元素個(gè)數(shù):

在PyObject結(jié)構(gòu)中,還有一個(gè)類型對(duì)象指針 ob_type ,用于表示Python對(duì)象是什么類型,定義Python對(duì)象類型的是一個(gè) PyTypeObject 接口體

實(shí)際定義是位于 Include/cpython/object.h 的 _typeobject :

在這個(gè)類型對(duì)象中,不僅包含了對(duì)象的類型,還包含了如分配內(nèi)存大小、對(duì)象標(biāo)準(zhǔn)操作等信息,主要分為:

以Python中的 int類型 為例,int類型對(duì)象的定義如下:

從PyObject的定義中我們知道,每個(gè)對(duì)象的 ob_type 都要指向一個(gè)具體的類型對(duì)象,比如一個(gè)數(shù)值型對(duì)象 100 ,它的ob_type會(huì)指向 int類型對(duì)象PyLong_Type 。

PyTypeObject結(jié)構(gòu)體第一行是一個(gè)PyObject_VAR_HEAD宏,查看宏定義可知PyTypeObject是一個(gè)變長(zhǎng)對(duì)象

也就是說,歸根結(jié)底 類型對(duì)象也是一個(gè)對(duì)象 ,也有ob_type屬性,那 PyLong_Type 的 ob_type 是什么呢?

回到PyLong_Type的定義,第一行 PyVarObject_HEAD_INIT(PyType_Type, 0) ,查看對(duì)應(yīng)的宏定義

由以上關(guān)系可以知道, PyVarObject_HEAD_INIT(PyType_Type, 0) = { { _PyObject_EXTRA_INIT 1, PyType_Type } 0} ,將其代入 PyObject_VAR_HEAD ,得到一個(gè)變長(zhǎng)對(duì)象:

這樣看就很明確了,PyLong_Type的類型就是PyType_Typ,同理可知, Python類型對(duì)象的類型就是PyType_Type ,而 PyType_Type對(duì)象的類型是它本身

從上述內(nèi)容中,我們知道了對(duì)象和對(duì)象類型的定義,那么根據(jù)定義,對(duì)象可以有以下兩種分類

Python對(duì)象定義有 PyObject 和 PyVarObject ,因此,根據(jù)對(duì)象大小是否可變的區(qū)別,Python對(duì)象可以劃分為 可變對(duì)象(變長(zhǎng)對(duì)象) 和 不可變對(duì)象(定長(zhǎng)對(duì)象)

原本的對(duì)象a大小并沒有改變,只是s引用的對(duì)象改變了。這里的對(duì)象a、對(duì)象b就是定長(zhǎng)對(duì)象

可以看到,變量l仍然指向?qū)ο骯,只是對(duì)象a的內(nèi)容發(fā)生了改變,數(shù)據(jù)量變大了。這里的對(duì)象a就是變長(zhǎng)對(duì)象

由于存在以上特性,所以使用這兩種對(duì)象還會(huì)帶來一種區(qū)別:

聲明 s2 = s ,修改s的值: s = 'new string' ,s2的值不會(huì)一起改變,因?yàn)橹皇莝指向了一個(gè)新的對(duì)象,s2指向的舊對(duì)象的值并沒有發(fā)生改變

聲明 l2 = l ,修改l的值: l.append(6) ,此時(shí)l2的值會(huì)一起改變,因?yàn)閘和l2指向的是同一個(gè)對(duì)象,而該對(duì)象的內(nèi)容被l修改了

此外,對(duì)于 字符串 對(duì)象,Python還有一套內(nèi)存復(fù)用機(jī)制,如果兩個(gè)字符串變量值相同,那它們將共用同一個(gè)對(duì)象:

對(duì)于 數(shù)值型 對(duì)象,Python會(huì)默認(rèn)創(chuàng)建0~2 8 以內(nèi)的整數(shù)對(duì)象,也就是 0 ~ 256 之間的數(shù)值對(duì)象是共用的:

按照Python數(shù)據(jù)類型,對(duì)象可分為以下幾類:

Python創(chuàng)建對(duì)象有兩種方式,泛型API和和類型相關(guān)的API

這類API通常以 PyObject_xxx 的形式命名,可以應(yīng)用在任意Python對(duì)象上,如:

使用 PyObjecg_New 創(chuàng)建一個(gè)數(shù)值型對(duì)象:

這類API通常只能作用于一種類型的對(duì)象上,如:

使用 PyLong_FromLong 創(chuàng)建一個(gè)數(shù)值型對(duì)象:

在我們使用Python聲明變量的時(shí)候,并不需要為變量指派類型,在給變量賦值的時(shí)候,可以賦值任意類型數(shù)據(jù),如:

從Python對(duì)象的定義我們已經(jīng)可以知曉造成這個(gè)特點(diǎn)的原因了,Python創(chuàng)建對(duì)象時(shí),會(huì)分配內(nèi)存進(jìn)行初始化,然后Python內(nèi)部通過 PyObject* 變量來維護(hù)這個(gè)對(duì)象,所以在Python內(nèi)部各函數(shù)直接傳遞的都是一種泛型指針 PyObject* ,這個(gè)指針?biāo)赶虻膶?duì)象類型是不固定的,只能通過所指對(duì)象的 ob_type 屬性動(dòng)態(tài)進(jìn)行判斷,而Python正是通過 ob_type 實(shí)現(xiàn)了多態(tài)機(jī)制

Python在管理維護(hù)對(duì)象時(shí),通過引用計(jì)數(shù)來判斷內(nèi)存中的對(duì)象是否需要被銷毀,Python中所有事物都是對(duì)象,所有對(duì)象都有引用計(jì)數(shù) ob_refcnt 。

當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)減少到0之后,Python將會(huì)釋放該對(duì)象所占用的內(nèi)存和系統(tǒng)資源。

但這并不意味著最終一定會(huì)釋放內(nèi)存空間,因?yàn)轭l繁申請(qǐng)釋放內(nèi)存會(huì)大大降低Python的執(zhí)行效率,因此Python中采用了內(nèi)存對(duì)象池的技術(shù),是的對(duì)象釋放的空間會(huì)還給內(nèi)存池,而不是直接釋放,后續(xù)需要申請(qǐng)空間時(shí),優(yōu)先從內(nèi)存對(duì)象池中獲取。

Python高級(jí)數(shù)據(jù)結(jié)構(gòu)——堆

在一個(gè) 最小堆 (min heap) 中,如果 P 是 C 的一個(gè)父級(jí)節(jié)點(diǎn),那么 P 的 key(或 value) 應(yīng)小于或等于 C 的對(duì)應(yīng)值。 正因?yàn)榇?,堆頂元素一定是最小的,我們?huì)利用這個(gè)特點(diǎn)求最小值或者第 k 小的值。

在一個(gè) 最大堆 (max heap) 中,P 的 key(或 value) 大于或等于 C 的對(duì)應(yīng)值。

以python為例,說明堆的幾個(gè)常見操作,這里需要用到一個(gè)內(nèi)置的包:heapq

python中使用堆是通過傳入一個(gè)數(shù)組,然后調(diào)用一個(gè)函數(shù),在原地讓傳入的數(shù)據(jù)具備堆的特性

需要注意的是,heapify默認(rèn)構(gòu)造的是小頂堆(min heap),如果要構(gòu)造大頂堆,思路是把所有的數(shù)值倒轉(zhuǎn),既* -1,例如:

使用heapq提供的函數(shù): heappop 來實(shí)現(xiàn)

具體使用方式參考 初始化Heapify

使用heapq提供的函數(shù): heappush 來實(shí)現(xiàn)

同時(shí)heapq還提供另外一個(gè)函數(shù): heappushpop ,能夠在一個(gè)函數(shù)實(shí)現(xiàn)pushpop兩個(gè)操作;順序是:先push再pop

根據(jù)官方文檔的描述,這個(gè)函數(shù)會(huì)比先在外圍先調(diào)用heappush,再調(diào)用heappop,效率更高

先pop數(shù)據(jù)再push數(shù)據(jù),和heappushpop的順序是反著的; 同樣的,這樣調(diào)用的性能也會(huì)比先調(diào)用heappop再調(diào)用heappush更好

如果pop的時(shí)候隊(duì)列是空的,會(huì)拋出一個(gè)異常

可以通過 heapq.merge 將多個(gè) 已排序 的輸入合并為一個(gè)已排序的輸出,這個(gè)本質(zhì)上不是堆;其實(shí)就是用兩個(gè)指針迭代

對(duì)于這個(gè)問題,有一個(gè)算法題可以實(shí)現(xiàn)相同的功能

從 iterable 所定義的數(shù)據(jù)集中返回前 n 個(gè)最大/小元素組成的列表。

函數(shù)為: heapq.nlargest() | heapq.nsmallest()

heapq - Heap queue algorithm - Python 3.10.4 documentation

python的內(nèi)存管理機(jī)制

論壇

活動(dòng)

招聘

專題

打開CSDN APP

Copyright ? 1999-2020, CSDN.NET, All Rights Reserved

登錄

XCCS_澍

關(guān)注

Python 的內(nèi)存管理機(jī)制及調(diào)優(yōu)手段? 原創(chuàng)

2018-08-05 06:50:53

XCCS_澍

碼齡7年

關(guān)注

內(nèi)存管理機(jī)制:引用計(jì)數(shù)、垃圾回收、內(nèi)存池。

一、引用計(jì)數(shù):

引用計(jì)數(shù)是一種非常高效的內(nèi)存管理手段, 當(dāng)一個(gè) Python 對(duì)象被引用時(shí)其引用計(jì)數(shù)增加 1, 當(dāng)其不再被一個(gè)變量引用時(shí)則計(jì)數(shù)減 1. 當(dāng)引用計(jì)數(shù)等于 0 時(shí)對(duì)象被刪除。

二、垃圾回收 :

1. 引用計(jì)數(shù)

引用計(jì)數(shù)也是一種垃圾收集機(jī)制,而且也是一種最直觀,最簡(jiǎn)單的垃圾收集技術(shù)。當(dāng) Python 的某個(gè)對(duì)象的引用計(jì)數(shù)降為 0 時(shí),說明沒有任何引用指向該對(duì)象,該對(duì)象就成為要被回收的垃圾了。比如某個(gè)新建對(duì)象,它被分配給某個(gè)引用,對(duì)象的引用計(jì)數(shù)變?yōu)?1。如果引用被刪除,對(duì)象的引用計(jì)數(shù)為 0,那么該對(duì)象就可以被垃圾回收。不過如果出現(xiàn)循環(huán)引用的話,引用計(jì)數(shù)機(jī)制就不再起有效的作用了

2. 標(biāo)記清除

如果兩個(gè)對(duì)象的引用計(jì)數(shù)都為 1,但是僅僅存在他們之間的循環(huán)引用,那么這兩個(gè)對(duì)象都是需要被回收的,也就是說,它們的引用計(jì)數(shù)雖然表現(xiàn)為非 0,但實(shí)際上有效的引用計(jì)數(shù)為 0。所以先將循環(huán)引用摘掉,就會(huì)得出這兩個(gè)對(duì)象的有效計(jì)數(shù)。

3. 分代回收

從前面“標(biāo)記-清除”這樣的垃圾收集機(jī)制來看,這種垃圾收集機(jī)制所帶來的額外操作實(shí)際上與系統(tǒng)中總的內(nèi)存塊的數(shù)量是相關(guān)的,當(dāng)需要回收的內(nèi)存塊越多時(shí),垃圾檢測(cè)帶來的額外操作就越多,而垃圾回收帶來的額外操作就越少;反之,當(dāng)需回收的內(nèi)存塊越少時(shí),垃圾檢測(cè)就將比垃圾回收帶來更少的額外操作。

python常用函數(shù)

1、complex()

返回一個(gè)形如?a+bj?的復(fù)數(shù),傳入?yún)?shù)分為三種情況:

參數(shù)為空時(shí),返回0j;參數(shù)為字符串時(shí),將字符串表達(dá)式解釋為復(fù)數(shù)形式并返回;參數(shù)為兩個(gè)整數(shù)(a,b)時(shí),返回?a+bj;參數(shù)只有一個(gè)整數(shù) a 時(shí),虛部 b 默認(rèn)為0,函數(shù)返回?a+0j。

2、dir()

不提供參數(shù)時(shí),返回當(dāng)前本地范圍內(nèi)的名稱列表;提供一個(gè)參數(shù)時(shí),返回該對(duì)象包含的全部屬性。

3、divmod(a,b)

a -- 代表被除數(shù),整數(shù)或浮點(diǎn)數(shù);b -- 代表除數(shù),整數(shù)或浮點(diǎn)數(shù);根據(jù) 除法運(yùn)算 計(jì)算 a,b 之間的商和余數(shù),函數(shù)返回一個(gè)元組(p,q)?,p 代表商?a//b?,q 代表余數(shù)?a%b。

4、enumerate(iterable,start=0)

iterable -- 一個(gè)可迭代對(duì)象,列表、元組序列等;start -- 計(jì)數(shù)索引值,默認(rèn)初始為0‘該函數(shù)返回枚舉對(duì)象是個(gè)迭代器,利用 next() 方法依次返回元素值,每個(gè)元素以元組形式存在,包含一個(gè)計(jì)數(shù)元素(起始為 start )和 iterable 中對(duì)應(yīng)的元素值。

Python的函數(shù)和參數(shù)

parameter 是函數(shù)定義的參數(shù)形式

argument 是函數(shù)調(diào)用時(shí)傳入的參數(shù)實(shí)體。

對(duì)于函數(shù)調(diào)用的傳參模式,一般有兩種:

此外,

也是關(guān)鍵字傳參

python的函數(shù)參數(shù)定義一般來說有五種: 位置和關(guān)鍵字參數(shù)混合 , 僅位置參數(shù) , 僅關(guān)鍵字參數(shù) , 可變位置參數(shù) , 可變關(guān)鍵字參數(shù) 。其中僅位置參數(shù)的方式僅僅是一個(gè)概念,python語(yǔ)法中暫時(shí)沒有這樣的設(shè)計(jì)。

通常我們見到的函數(shù)是位置和關(guān)鍵字混合的方式。

既可以用關(guān)鍵字又可以用位置調(diào)用

這種方式的定義只能使用關(guān)鍵字傳參的模式

f(*some_list) 與 f(arg1, arg2, ...) (其中some_list = [arg1, arg2, ...])是等價(jià)的

網(wǎng)絡(luò)模塊request的request方法的設(shè)計(jì)

多數(shù)的可選參數(shù)被設(shè)計(jì)成可變關(guān)鍵字參數(shù)

有多種方法能夠?yàn)楹瘮?shù)定義輸出:

非?;逎?/p>

如果使用可變對(duì)象作為函數(shù)的默認(rèn)參數(shù),會(huì)導(dǎo)致默認(rèn)參數(shù)在所有的函數(shù)調(diào)用中被共享。

例子1:

addItem方法的data設(shè)計(jì)了一個(gè)默認(rèn)參數(shù),使用不當(dāng)會(huì)造成默認(rèn)參數(shù)被共享。

python里面,函數(shù)的默認(rèn)參數(shù)被存在__default__屬性中,這是一個(gè)元組類型

例子2:

在例子1中,默認(rèn)參數(shù)是一個(gè)列表,它是mutable的數(shù)據(jù)類型,當(dāng)它寫進(jìn) __defauts__屬性中時(shí),函數(shù)addItem的操作并不會(huì)改變它的id,相當(dāng)于 __defauts__只是保存了data的引用,對(duì)于它的內(nèi)存數(shù)據(jù)并不關(guān)心,每次調(diào)用addItem,都可以修改 addItem.__defauts__中的數(shù)據(jù),它是一個(gè)共享數(shù)據(jù)。

如果默認(rèn)參數(shù)是一個(gè)imutable類型,情況將會(huì)不一樣,你無(wú)法改變默認(rèn)參數(shù)第一次存入的值。

例子1中,連續(xù)調(diào)用addItem('world') 的結(jié)果會(huì)是

而不是期望的

python中函數(shù)的作用

Python 函數(shù)定義以及參數(shù)傳遞

1.函數(shù)定義

#形如def func(args...):

doSomething123

以關(guān)鍵字def 開頭,后面是函數(shù)名和參數(shù)下面是函數(shù)處理過程。

舉例:

def add( a, b ):

return a+b12

參數(shù)可以設(shè)定默認(rèn)值,如:

def add( a, b=10 ): #注意:默認(rèn)值參數(shù)只會(huì)運(yùn)算一次

return a+b12

默認(rèn)值參數(shù)只會(huì)運(yùn)算一次是什么意思?

def func( a, b=[] ): #b的默認(rèn)值指向一個(gè)空的列表,每次不帶默認(rèn)值都會(huì)指向這塊內(nèi)存

b.append(a) return b

print(func(1))#向默認(rèn)的空列表里加入元素1 ,默認(rèn)列表里已經(jīng)是[1]print(func(2))#向默認(rèn)的列表里加入元素2,默認(rèn)列表里已經(jīng)是[1,2]print(func(3,[]))#向b指向的空列表里加入元素1 ,默認(rèn)列表里還是[1,2]print(func(4))#向默認(rèn)的列表里加入元素4,默認(rèn)列表里已經(jīng)是[1,2,4]'''

結(jié)果:

[1]

[1, 2]

[3]

[1, 2, 4]

'''12345678910111213141516

這下明白為什么默認(rèn)參數(shù)只計(jì)算一次了吧,函數(shù)參數(shù)不傳遞時(shí)默認(rèn)值總是指向固定的內(nèi)存空間,就是第一次計(jì)算的空間。

2.參數(shù)傳遞

def func(a, b):

print('a=%d, b=%d' % (a,b) )12

在使用函數(shù)時(shí)可以如下方式,結(jié)果都是相同的

func(10,20) #不使用參數(shù)名,需要按參數(shù)順序傳遞func(a=10,b=20) #使用參數(shù)名可以不按順序傳遞func(b=20,a=10)#結(jié)果:a=10, b=20a=10, b=20a=10, b=201234567

如果函數(shù)定義形式如下方式:

def func(*args): #這種定義會(huì)把傳遞的參數(shù)包成元組

print(args,type(args))

func(10,20)#結(jié)果:#(10, 20) class 'tuple'1234567

舉一個(gè)和上述過程相反的例子:

def func(a,b):

print('a=%d, b=%d' % (a,b) )

a = (10, 20)

func(*a) #在調(diào)用函數(shù)使用`*`則會(huì)把元組解包成單個(gè)變量按順序傳入函數(shù)#結(jié)果:a=10, b=20123456

總結(jié):*號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成元組,如果 *號(hào)在調(diào)用時(shí)則會(huì)把元組解包成單個(gè)元素。

另一種定義:

def func(**kw):#使用**定義參數(shù)會(huì)把傳入?yún)?shù)包裝成字典dict

print(kw, type(kw) )

func(a=10,b=20)#這種函數(shù)在使用時(shí)必須指定參數(shù)值,使用key=value這種形式#結(jié)果:{'b': 20, 'a': 10} class 'dict'12345

相反的例子:

def func(a,b):

print('a=%d, b=%d' % (a,b) )

d = {'a':10, 'b':20 }

func(**d) #在調(diào)用時(shí)使用**會(huì)把字典解包成變量傳入函數(shù)。12345

def func(*args, **kw):#這種形式的定義代表可以接受任意類型的參數(shù)

print(args,kw )12

總結(jié):**號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成字典,如果 **號(hào)在調(diào)用時(shí)則會(huì)把字典解包成單個(gè)元素。

lambda表達(dá)式

lambda表達(dá)式就是一種簡(jiǎn)單的函數(shù)

形如 f = lambda 參數(shù)1,參數(shù)2: 返回的計(jì)算值

例如:

add = lambda x,y: x+y

print(add(1,2))'''

結(jié)果:3

'''12345

標(biāo)題名稱:python的函數(shù)存在堆,Python堆
分享鏈接:http://jinyejixie.com/article44/hopdhe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航App開發(fā)、移動(dòng)網(wǎng)站建設(shè)網(wǎng)站設(shè)計(jì)、企業(yè)網(wǎng)站制作、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)
天气| 平安县| 红安县| 台前县| 怀仁县| 资溪县| 郧西县| 射阳县| 莱芜市| 六安市| 凉城县| 凉城县| 吉木乃县| 无锡市| 南宫市| 华池县| 中江县| 池州市| 宕昌县| 肇东市| 子洲县| 镇江市| 阿瓦提县| 恩施市| 乳源| 兴城市| 新丰县| 措美县| 浮山县| 牡丹江市| 景泰县| 凤城市| 遂平县| 宜州市| 永德县| 平凉市| 梧州市| 自治县| 巴东县| 瓦房店市| 石楼县|