Python編程學(xué)習(xí)筆記_第1頁(yè)
Python編程學(xué)習(xí)筆記_第2頁(yè)
Python編程學(xué)習(xí)筆記_第3頁(yè)
Python編程學(xué)習(xí)筆記_第4頁(yè)
Python編程學(xué)習(xí)筆記_第5頁(yè)
已閱讀5頁(yè),還剩202頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Python

編程學(xué)習(xí)筆記

目錄

第一部分Python語(yǔ)言9

第1章基本環(huán)境10

1.1虛擬機(jī)10

1.2類型和對(duì)象10

1.3名字空間12

1.4內(nèi)存管理14

1.5編譯20

1.6執(zhí)行22

第2章內(nèi)置類型24

2.1數(shù)字24

2.2字符串27

2.3列表33

2.4元組35

2.5字典36

2.6集合41

第3章表達(dá)式45

3.1句法規(guī)則45

3.2命名規(guī)則47

3.3賦值48

3.4表達(dá)式49

3.5運(yùn)算符54

3.6類型轉(zhuǎn)換58

3.7常用函數(shù)58

第4章函數(shù)61

4

4.1創(chuàng)建61

4.2參數(shù)62

4.3作用域64

4.4閉包69

4.5堆棧幀71

4.6包裝73

第5章迭代器74

5.1迭代器74

5.2生成器75

5.3模式77

5.4寶藏79

第6章模塊84

6.1模塊對(duì)象84

6.2搜索路徑85

6.3導(dǎo)入模塊86

6.4構(gòu)建包89

第7章類93

7.1名字空間93

7.2字段94

7.3屬性96

7.4方法99

7.5繼承102

7.6開(kāi)放類109

7.7操作符重載112

第8章異常116

8.1異常116

5

8.2斷言118

8.3上下文118

第9章裝飾器122

第10章描述符128

第11章元類132

第二部分標(biāo)準(zhǔn)庫(kù)136

第12章字符串137

12.1re137

12.2StringIO143

12.3struct143

第13章數(shù)據(jù)類型145

13.1bisect145

13.2heapq146

第14章數(shù)學(xué)運(yùn)算149

14.1random149

第15章文件與皿錄152

15.1file152

15.2binary153

15.3encoding154

15.4descriptor154

15.5tempfile155

15.6os.path156

15.7os158

15.8shutil160

第16章數(shù)據(jù)存儲(chǔ)161

16.1serialization161

6

16.2shevle163

第17章數(shù)據(jù)壓縮164

第18章格式解析165

第19章數(shù)據(jù)加密166

第20章操作系統(tǒng)167

20.1time167

20.2threading169

20.3multiprocessing174

20.4argparse179

20.5ctypes186

第21章進(jìn)程通信188

21.1subprocess188

22.2signal189

第22章絡(luò)編程192

第23章程序框架193

23.1cmd193

23.2shlex194

第24章開(kāi)發(fā)工具196

第25章運(yùn)行時(shí)服務(wù)197

第26章語(yǔ)言服務(wù)198

第三部分?jǐn)U展庫(kù)199

A.Fabric200

附錄203

A.CPython204

B.IPython205

7

C.PDB207

D.PIP-install208

E.VirtualEnv209

8

第一部分Python語(yǔ)言

Python2.7語(yǔ)言相關(guān)

9

第1章基本環(huán)境

1.1虛擬機(jī)

Python是一種半編譯半解釋型運(yùn)行環(huán)境。首先,它會(huì)在模塊"載入"時(shí)將源碼編譯成字節(jié)碼(Byte

Code)o而后,這些字節(jié)碼會(huì)被虛擬機(jī)在一個(gè)“巨大”的核心函數(shù)里解釋執(zhí)行。這是導(dǎo)致Python性

能較低的重要原因,好在現(xiàn)在有了內(nèi)置Just-in-time二次編譯器的PvPv可供選擇。

當(dāng)虛擬機(jī)開(kāi)始運(yùn)行時(shí),它通過(guò)初始化函數(shù)完成整個(gè)運(yùn)行環(huán)境設(shè)置:

?創(chuàng)建解釋器和主線程狀態(tài)對(duì)象,這是整個(gè)進(jìn)程的根對(duì)象。

?初始化內(nèi)置類型。數(shù)字、列表等類型都有專的緩存策略需要處理。

?創(chuàng)建_bui田n_模塊,該模塊持有所有內(nèi)置類型和函數(shù)。

?創(chuàng)建sys模塊,其中包含了sys.path、modules等重要的運(yùn)行期信息。

?初始化import機(jī)制。

?初始化內(nèi)置Exceptiono

?創(chuàng)建_main_模塊,準(zhǔn)備運(yùn)行所需的名字空間。

?通過(guò)s讓e.py將s讓e-packages中的第三方擴(kuò)展庫(kù)添加到搜索路徑列表。

?執(zhí)行入口py文件。執(zhí)行前會(huì)將_main.dict_作為名字空間傳遞進(jìn)去。

?程序執(zhí)行結(jié)束。

?執(zhí)行清理操作,包括調(diào)用退出函數(shù),GC清理現(xiàn)場(chǎng),釋放所有模塊等。

?終止進(jìn)程。

Python源碼是個(gè)寶庫(kù),其中有大量的編程范式和技巧可供借鑒,尤其是對(duì)內(nèi)存的管理分配。個(gè)人

建議有C基礎(chǔ)的兄弟,在閑暇時(shí)翻看一二。

1.2類型和對(duì)象

先有類型(Type),而后才能生成實(shí)例(Instance)。Python中的一切都是對(duì)象,包括類型在內(nèi)的每

個(gè)對(duì)象都包含一個(gè)標(biāo)準(zhǔn)頭,通過(guò)頭部信息就可以明確知道其具體類型。

頭信息由“引用計(jì)數(shù)"和“類型指針”組成,前者在對(duì)象被引用時(shí)增加,超出作用域或手工釋放后減

小,等于0時(shí)會(huì)被虛擬機(jī)回收(某些被緩存的對(duì)象計(jì)數(shù)器永遠(yuǎn)不會(huì)為0)。

以int為例,對(duì)應(yīng)Python結(jié)構(gòu)定義是:

#definePyObject_HEAD\

Py_ssize_tob_refcnt;\

structJypeobject*ob_type;

typedefstruct_object{

PyObject_HEAD

10

}PyObject;

typedefstruct{

PyObject_HEAD〃在64位版本中,頭度為16字節(jié)。

longobjval;//long是8字節(jié)。

}PylntObject;

可以用sys中的函數(shù)測(cè)試一下。

?>importsys

?>x=0x1234#不要使用卜5,257)之間的小數(shù)字,它們有專的緩存機(jī)制。

?>sys.getsizeof(x)#符合度預(yù)期。

24

?>sys.getrefcount(x)#sys.getrefcount()讀取頭部引用計(jì)數(shù),注意形參也會(huì)增加一次引用。

2

>?y=x#引用計(jì)數(shù)增加。

?>sys.getrefcount(x)

3

?>dely#引用計(jì)數(shù)減小。

?>sys.getrefcount(x)

2

類型指針則指向具體的類型對(duì)象,其中包含了繼承關(guān)系、靜態(tài)成員等信息。所有的內(nèi)置類型對(duì)象都

能從types模塊中找到,至于int、long、str這些關(guān)鍵字可以看做是簡(jiǎn)短別名。

?>importtypes

?>x=20

?>type(x)istypes.lntType#is通過(guò)指針判斷是否指向同一對(duì)象。

True

>?x._class—#_class_通過(guò)類型指針來(lái)獲取類型對(duì)象。

<type'int'>

?>x._class_istype(x)isintistypes.lntType

True

?>y=x

?>hex(id(x))5hex(id(y))#id()返回對(duì)象標(biāo)識(shí),其實(shí)就是內(nèi)存地址。

('0x7fc5204103c0','0x7fc5204103c0,)

11

?>hex(id(int)),hex(id(types.lntType))

('0x1088cebd8','0x1088cebd8')

除了int這樣的固定度類型外,還有l(wèi)ong、str這類變對(duì)象。其頭部多出一個(gè)記錄元素項(xiàng)數(shù)量

的字段。比如str的字節(jié)數(shù)量,list列表的度等等。

#definePyObject_VAR_HEAD\

PyObject_HEAD\

Py_ssize_tob_size;/*Numberofitemsinvariablepart*/

typedefstruct{

PyObject_VAR_HEAD

}PyVarObject;

有關(guān)類型和對(duì)象更多的信息,將在后續(xù)章節(jié)中詳述。

1.3名字空間

名字空間是Python最核心的內(nèi)容。

?>X

NameError:name'x'isnotdefined

我們習(xí)慣于將X稱為變量,但在這里,更準(zhǔn)確的詞語(yǔ)是“名字”。

和C變量名是內(nèi)存地址別名不同,Python的名字實(shí)際上是一個(gè)字符串對(duì)象,它和所指向的皿標(biāo)對(duì)

象一起在名字空間中構(gòu)成一項(xiàng){name:object}關(guān)聯(lián)。

Python有多種名字空間,比如稱為globals的模塊名字空間,稱為locals的函數(shù)堆棧幀名字空

間,還有class、instance名字空間。不同的名字空間決定了對(duì)象的作用域和生存周期。

?>x=123

?>globals()#獲取module名字空間。

{'X':123,……}

可以看出,名字空間就是一個(gè)字典(diet)。我們完全可以直接在名字空間添加項(xiàng)來(lái)創(chuàng)建名字。

?>globals()["y"]="Hello,World!"

?>y

'Hello,World!'

在Python源碼中,有這樣一句話:Nameshavenotype,butobjectsdo.

12

名字的作用僅僅是在某個(gè)時(shí)刻與名字空間中的某個(gè)對(duì)象進(jìn)行關(guān)聯(lián)。其本身不包含皿標(biāo)對(duì)象的任何信

息,只有通過(guò)對(duì)象頭部的類型指針才能獲知其具體類型,進(jìn)而查找其相關(guān)成員數(shù)據(jù)。正因?yàn)槊值?/p>

弱類型特征,我們可以在運(yùn)行期隨時(shí)將其關(guān)聯(lián)到任何類型對(duì)象。

?>y

'Hello,World!'

?>type(y)

<type'str'>

?>y=_import_(”string”)#將原本與字符串關(guān)聯(lián)的名字指向模塊對(duì)象。

?>type(y)

<type'modules

?>y.digits#查看模塊對(duì)象的成員。

,0123456789,

在函數(shù)外部,locals。和globals。作用完全相同。而當(dāng)在函數(shù)內(nèi)部調(diào)用時(shí),locals。則是獲取當(dāng)前

函數(shù)堆棧幀的名字空間,其中存儲(chǔ)的是函數(shù)參數(shù)、局部變量等信息。

?>importsys

?>globals()islocals()

True

?>locals()

(

,—builtins_<module'_builtin—'(built-in)>,

'_name__main_

'sys':<module'sys'(built-in)>,

)

?>deftest(x):#請(qǐng)對(duì)比下面的輸出內(nèi)容。

...y=x+100

...printlocals()#可以看到locals名字空間中包含當(dāng)前局部變量。

…printglobals()islocals()#此時(shí)locals和globals指向不同名字空間。

...frame=sys._getframe(O)#_getframe(O)獲取當(dāng)前堆棧幀。

■■■printlocals()isframe.fjocals#locals名字空間實(shí)際就是當(dāng)前堆棧幀的名字空間。

...printglobals()isframe.f_globals#通過(guò)什ame我們也可以函數(shù)定義模塊的名字空間。

?>test(123)

{'y':223,'x':123}

False

True

True

13

在函數(shù)中調(diào)用globals()時(shí),總是獲取包含該函數(shù)定義的模塊名字空間,而非調(diào)用處。

?>pycattest.py

a=1

deftest():

print{k:vfork,vinglobals().items()ifk!="_builtins_"}

?>importtest

?>test.test()

(

'file—'test.pyc',

'—name—'test',

'a':1,

'test':<functiontestat0x10bd85e60>,

可通過(guò)〈module〉.—diet—訪問(wèn)其他模塊的名字空間。

?>test._diet_#test模塊的名字空間

{

1file_'test.pyc",

'—name—'test',

'a':1,

'test':<functiontestat0x10bd85e60>,

}

?>importsys

?>sys.modules[_name_]._diet_isglobals()#當(dāng)前模塊名字空間和globals相同。

True

與名字空間有關(guān)的內(nèi)容很多,比如作用域、LEGB查找規(guī)則、成員查找規(guī)則等等。所有這些,都將

在相關(guān)章節(jié)中給出詳細(xì)說(shuō)明。

使用名字空間管理上下文對(duì)象,帶來(lái)無(wú)與倫比的靈活性,但也犧牲了執(zhí)行性能。畢竟從字典中查找

對(duì)象遠(yuǎn)比指針低效很多,各有得失。

1.4內(nèi)存管理

為提升執(zhí)行性能,Python在內(nèi)存管理上做了大量工作。最直接的做法就是用內(nèi)存池來(lái)減少操作系

統(tǒng)內(nèi)存分配和回收操作,那些小于等于256字節(jié)對(duì)象,將直接從內(nèi)存池中獲取存儲(chǔ)空間。

根據(jù)需要,虛擬機(jī)每次從操作系統(tǒng)申請(qǐng)一塊256KB,取名為arena的大塊內(nèi)存。并按系統(tǒng)大

小,劃分成多個(gè)pool。每個(gè)pool繼續(xù)分割成n個(gè)大小相同的block,這是內(nèi)存池最小存儲(chǔ)單位。

14

block大小是8的倍數(shù),也就是說(shuō)存儲(chǔ)13字節(jié)大小的對(duì)象,需要找block大小為16的pool獲

取空閑塊。所有這些都用頭信息和鏈表管理起來(lái),以便快速查找空閑區(qū)域進(jìn)行分配。

大于256字節(jié)的對(duì)象,直接用malloc在堆上分配內(nèi)存。程序運(yùn)行中的絕大多數(shù)對(duì)象都小于這個(gè)閾

值,因此內(nèi)存池策略可有效提升性能。

當(dāng)所有arena的總?cè)萘砍鱿拗?64MB)時(shí),就不再請(qǐng)求新的arena內(nèi)存。而是如同“大對(duì)象"一

樣,直接在堆上為對(duì)象分配內(nèi)存。另外,完全空閑的arena會(huì)被釋放,其內(nèi)存交還給操作系統(tǒng)。

引用傳遞

對(duì)象總是按引用傳遞,簡(jiǎn)單點(diǎn)說(shuō)就是通過(guò)復(fù)制指針來(lái)實(shí)現(xiàn)多個(gè)名字指向同一對(duì)象。因?yàn)閍rena也是

在堆上分配的,所以無(wú)論何種類型何種大小的對(duì)象,都存儲(chǔ)在堆上。Python沒(méi)有值類型和引用類

型一說(shuō),就算是最簡(jiǎn)單的整數(shù)也是擁有標(biāo)準(zhǔn)頭的完整對(duì)象。

?>a=object()

?>b=a

?>aisb

True

>?hex(id(a))5hex(id(b))#地址相同,意味著對(duì)象是同一個(gè)。

('0x10b1f5640','0x10b1f5640')

?>deftest(x):

...printhex(id(x))

?>test(a)

0x10b1f5640#地址依舊相同。

如果不希望對(duì)象被修改,就需使用不可變類型,或?qū)ο髲?fù)制品。

不可變類型:int,long,str,tuple,frozenset

除了某些類型自帶的copy方法外,還可以:

?使用標(biāo)準(zhǔn)庫(kù)的copy模塊進(jìn)行深度復(fù)制。

?序列化對(duì)象,如pickle、cPickle、marshal0

下面的測(cè)試建議不要用數(shù)字等不可變對(duì)象,因?yàn)槠鋬?nèi)部的緩存和復(fù)用機(jī)制可能會(huì)造成干擾。

?>importcopy

?>x=object()

?>l=[x]#創(chuàng)建一個(gè)列表。

15

?>12=copy.copy(l)#淺復(fù)制,僅復(fù)制對(duì)象自身,而不會(huì)遞歸復(fù)制其成員。

?>12isI#可以看到復(fù)制列表的元素依然是原對(duì)象。

False

?>12[0]isx

True

?>13=copy.deepcopy(l)#深度復(fù)制,會(huì)遞歸復(fù)制所有深度成員。

?>13isI#列表元素也被復(fù)制了。

False

?>13[0]isx

False

循環(huán)引用會(huì)影響deepcopy函數(shù)的運(yùn)作,建議查閱官方標(biāo)準(zhǔn)庫(kù)文檔。

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

Python默認(rèn)采用引用計(jì)數(shù)來(lái)管理對(duì)象的內(nèi)存回收。當(dāng)引用計(jì)數(shù)為0時(shí),將立即回收該對(duì)象內(nèi)存,

要么將對(duì)應(yīng)的block塊標(biāo)記為空閑,要么返還給操作系統(tǒng)。

為觀察回收行為,我們用—del_監(jiān)控對(duì)象釋放。

?>classUser(object):

...def_del—(self):

...print"Willbedead!"

?>a=User()

?>b=a

?>importsys

?>sys.getrefcount(a)

3

?>dela#刪除引用,計(jì)數(shù)減小。

?>sys.getrefcount(b)

2

?>delb#刪除最后一個(gè)引用,計(jì)數(shù)器為0,對(duì)象被回收。

Willbedead!

某些內(nèi)置類型,比如小整數(shù),因?yàn)榫彺娴木壒?,?jì)數(shù)永遠(yuǎn)不會(huì)為0,直到進(jìn)程結(jié)束才由虛擬機(jī)清理

函數(shù)釋放。

除了直接引用外,Python還支持弱引用。允許在不增加引用計(jì)數(shù),不妨礙對(duì)象回收的情況下間接

引用對(duì)象。但不是所有類型都支持弱引用,比如list、diet,弱引用會(huì)引發(fā)異常。

16

改用弱引用回調(diào)監(jiān)控對(duì)象回收。

?>importsys,weakref

?>classUser(object):pass

?>defcallback(r):#回調(diào)函數(shù)會(huì)在原對(duì)象被回收時(shí)調(diào)用。

...print"weakrefobject:",r

...print"targetobjectdead!"

?>a=User()

?>r=weakref.ref(a,callback)#創(chuàng)建弱引用對(duì)象。

?>sys.getrefcount(a)#可以看到弱引用沒(méi)有導(dǎo)致皿標(biāo)對(duì)象引用計(jì)數(shù)增加。

2#計(jì)數(shù)2是因?yàn)間etrefcount形參造成的。

?>r()isa#透過(guò)弱引用可以訪問(wèn)原對(duì)象。

True

?>dela#原對(duì)象回收,callback被調(diào)用。

weakrefobject:<weakrefat0x10f99a368;dead>

targetobjectdead!

?>hex(id(r))#通過(guò)對(duì)比,可以看到callback參數(shù)是弱引用對(duì)象。

'0x1Of99a368'#因?yàn)樵瓕?duì)象已經(jīng)死亡。

?>r()isNone#此時(shí)弱引用只能返回None0也可以此判斷原對(duì)象死亡。

True

引用計(jì)數(shù)是一種簡(jiǎn)單直接,并且十分高效的內(nèi)存回收方式。大多數(shù)時(shí)候它都能很好地工作,除了循

環(huán)引用造成計(jì)數(shù)故障。簡(jiǎn)單明顯的循環(huán)引用,可以用弱引用打破循環(huán)關(guān)系。但在實(shí)際開(kāi)發(fā)中,循環(huán)

引用的形成往往很復(fù)雜,可能由n個(gè)對(duì)象間接形成一個(gè)大的循環(huán)體,此時(shí)只有靠GC去回收了。

垃圾回收

事實(shí)上,Python擁有兩套垃圾回收機(jī)制。除了引用計(jì)數(shù),還有個(gè)專處理循環(huán)引用的GCo通常我

們提到垃圾回收時(shí),都是指這個(gè)"ReferenceCycleGarbageCollection"0

能引發(fā)循環(huán)引用問(wèn)題的,都是那種容器類對(duì)象,比如list、set、object等。對(duì)于這類對(duì)象,虛擬

機(jī)在為其分配內(nèi)存時(shí),會(huì)額外添加用于追蹤的PyGCJHead。這些對(duì)象被添加到特殊鏈表里,以便

GC進(jìn)行管理。

typedefunion_gc_head{

struct{

union_gc_head*gc_next;

17

union_gc_head*gc_prev;

Py_ssize_tgc_refs;

}gc;

longdoubledummy;

}PyGC_Head;

當(dāng)然,這并不表示此類對(duì)象非得GC才能回收。如果不存在循環(huán)引用,自然是積極性更高的引用計(jì)

數(shù)機(jī)制搶先給處理掉。也就是說(shuō),只要不存在循環(huán)引用,理論上可以禁用GC。當(dāng)執(zhí)行某些密集運(yùn)

算時(shí),臨時(shí)關(guān)掉GC有助于提升性能。

?>importgc

?>classUser(object):

...def_del—(self):

.printhex(id(self)),"w川bedead!"

?>gc.disable()#關(guān)掉GC

?>a=User()

?>dela#對(duì)象正?;厥?,引用計(jì)數(shù)不會(huì)依賴GCo

0x10fddf590willbedead!

同.NET、JAVA一樣,PythonGC同樣將要回收的對(duì)象分成3級(jí)代齡。GEN0管理新近加入的年

輕對(duì)象,GEN1則是在上次回收后依然存活的對(duì)象,剩下GEN2存儲(chǔ)的都是生命周期極的家伙。

每級(jí)代齡都有一個(gè)最大容量閾值,每次GEN0對(duì)象數(shù)量超出閾值時(shí),都將引發(fā)垃圾回收操作。

#defineNUM_GENERATIONS3

/*linkedlistsofcontainerobjects7

staticstructgc_generationgenerations[NUM_GENERATIONS]={

/*PyGC_Head,threshold,count*/

{{{GEN_HEAD(0),GEN_HEAD(0),0}},700,0).

{{{GENJHEAD⑴,GEN_HEAD(1),0}},10,0}.

{{{GEN_HEAD(2),GEN_HEAD(2),0}},10,0).

);

GC首先檢查GEN2,如閾值被突破,那么合并GEN2、GEN1、GEN0幾個(gè)追蹤鏈表。如果沒(méi)有超

出,則檢查GENLGC將存活的對(duì)象提升代齡,而那些可回收對(duì)象則被打破循環(huán)引用,放到專

的列表等待回收。

?>gc.get_threshold()#獲取各級(jí)代齡閾值

(700,10,10)

?>gc.get_count()#各級(jí)代齡鏈表跟蹤的對(duì)象數(shù)量

(203,0,5)

包含—del_方法的循環(huán)引用對(duì)象,永遠(yuǎn)不會(huì)被GC回收,直至進(jìn)程終止。

18

這回不能偷懶用—del—監(jiān)控對(duì)象回收了,改用weakrefo因IPython對(duì)GC存在干擾,下面的測(cè)

試代碼建議在原生shell中進(jìn)行。

?>importgc,weakref

?>classUser(object):pass

?>defcallback(r):printr,"dead"

?>gc.disable()#停掉GC,看看引用計(jì)數(shù)的能力。

?>a=User();wa=weakref.ref(a,callback)

?>b=User();wb=weakref.ref(b,callback)

?>a.b=b;b.a=a#形成循環(huán)引用關(guān)系。

?>dela;delb#刪除名字引用。

?>wa(),wb()#顯然,計(jì)數(shù)機(jī)制對(duì)循環(huán)引用無(wú)效。

(<_main_.Userobjectat0x1045f4f50>,<_main_.Userobjectat0x1045f4f90>)

?>gc.enable()#開(kāi)啟GCo

?>gc.isenabled()#可以用isenabled確認(rèn)。

True

?>gc.collect()#因?yàn)闆](méi)有達(dá)到閾值,我們手工啟動(dòng)回收。

<weakrefat0x1045a8cb0;dead>dead#GC的確有對(duì)付基友的能力。

<weakrefat0x1045a8db8;dead>dead#這個(gè)地址是弱引用對(duì)象的,別犯糊涂。

一旦有了_del_,GC就拿循環(huán)引用沒(méi)辦法了。

?>importgc,weakref

?>classUser(object):

...def_del_(self):pass#難道連空的_del_也不行?

?>defcallback(r):printr,"dead!"

?>gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_LEAK)#輸出更詳細(xì)的回收狀態(tài)信息。

?>gc.isenabled()#確保GC在工作。

True

?>a=User();wa=weakref.ref(a,callback)

?>b=User();wb=weakref.ref(b,callback)

?>a.b=b;b.a=a

?>dela;delb

?>gc.collect()#從輸出信息看,回收失敗。

gc:collectinggeneration2...

19

gc:objectsineachgeneration:52031900

gc:uncollectable<User0x10fd51fd0>#a

gc:uncollectable<User0x10fd57050>#b

gc:uncollectable<dict0x7f990ac88280>#a._diet.

gc:uncollectable<dict0x7f990ac88940>#b._diet.

gc:done,4unreachable,4uncollectable,0.0014selapsed.

4

?>xa=wa()

?>xa,hex(id(xa.—diet))

<_main_.Userobjectat0x10fd51fd0>,'0x7f990ac88280,,

?>xb=wb()

?>xb,hex(id(xb.—diet))

<_main_.Userobjectat0x10fd57050>,'0x7f990ac88940'

關(guān)于用不用_del_的爭(zhēng)論很多。大多數(shù)人的結(jié)論是堅(jiān)決抵制,諸多“牛人”也是這樣教導(dǎo)新手的。

可畢竟_del_承擔(dān)了析構(gòu)函數(shù)的角色,某些時(shí)候還是有其特定的作用的。用弱引用回調(diào)會(huì)造成邏

輯分離,不便于維護(hù)。對(duì)于一些簡(jiǎn)單的腳本,我們還是能保證避免循環(huán)引用的,那不妨試試。就像

前面例子中用來(lái)監(jiān)測(cè)對(duì)象回收,就很方便。

1.5編譯

Python實(shí)現(xiàn)了棧式虛擬機(jī)(Stack-BasedVM)架構(gòu),通過(guò)與機(jī)器無(wú)關(guān)的字節(jié)碼來(lái)實(shí)現(xiàn)跨平臺(tái)執(zhí)行

能力。這種字節(jié)碼指令集沒(méi)有寄存器,完全以棧(抽象層面)進(jìn)行指令運(yùn)算。盡管很簡(jiǎn)單,但對(duì)普通

開(kāi)發(fā)人員而言,是無(wú)需關(guān)心的細(xì)節(jié)。

要運(yùn)行Python語(yǔ)言編寫(xiě)的程序,必須將源碼編譯成字節(jié)碼。通常情況下,編譯器會(huì)將源碼轉(zhuǎn)換成

字節(jié)碼后保存在pyc文件中。還可用Q參數(shù)生成py。格式,這是簡(jiǎn)單優(yōu)化后的pyc文件。

編譯發(fā)生在模塊載入那一刻。具體來(lái)看,又分為pyc和py兩種情況。

載入pyc流程:

?核對(duì)文件Magic標(biāo)記。

?檢查時(shí)間戳和源碼文件修改時(shí)間是否相同,以確定是否需要重新編譯。

?載入模塊。

如果沒(méi)有pyc,那么就需要先完成編譯:

?對(duì)源碼進(jìn)行AST分析。

?將分析結(jié)果編譯成PyCodeObjecto

?將Magic、源碼文件修改時(shí)間、PyCodeObject保存到pyc文件中。

?載入模塊。

20

Magic是一個(gè)特殊的數(shù)字,由Python版本號(hào)計(jì)算得來(lái),作為pyc文件和Python版本檢查標(biāo)記。

PyCodeObject則包含了代碼對(duì)象的完整信息。

typedefstruct{

PyObject_HEAD

intco_argcount;//參數(shù)個(gè)數(shù),不包括*args,**kwargs.

intco_nlocals;//局部變量數(shù)量。

intco_stacksize;//執(zhí)行所需的??臻g。

intco_flags;〃編譯標(biāo)志,在創(chuàng)建Frame時(shí)用得著。

PyObject*co_code;//字節(jié)碼指令。

PyObject*co_consts;//常量列表。

PyObject*co_names;//符號(hào)列表。

PyObject*co_varnames;//局部變量名列表。

PyObject*co_freevars;〃閉包:引用外部函數(shù)名字列表。

PyObject*co_cellvars;〃閉包:被內(nèi)部函數(shù)引用的名字列表。

PyObject*co_filename;//源碼文件名。

PyObject*co_name;//PyCodeObject的名字,函數(shù)名、類名什么的。

intco_firstlineno;〃這個(gè)PyCodeObject在源碼文件中的起始位置,也就是行號(hào)。

PyObject*co_lnotab;//字節(jié)碼指令偏移量和源碼行號(hào)的對(duì)應(yīng)關(guān)系,反匯編時(shí)用得著。

void*co_zombieframe;〃為優(yōu)化準(zhǔn)備的特殊Frame對(duì)象。

PyObject*co_weakreflist;〃為弱引用準(zhǔn)備的…

}PyCodeObject;

無(wú)論是模塊還是其內(nèi)部的函數(shù),都被編譯成PyCodeObject對(duì)象。內(nèi)部成員都嵌套到co_consts

列表中。

?>pycattest.py

Hello,World!

defadd(a,b):

returna+b

c=add(10,20)

?>code=compile(open("test.pyn).read(),"test.py","exec")

?>code.co_filename,code.co_name,code.co_names

('test.py',,<module>,,fdoc_'add','c'))

?>code.co_consts

(1\nHello,World!\n',<codeobjectaddat0x105b76e30,file"test.py",line5>,10,

20,None)

?>add=code.co_consts[1]

?>add.co_varnames

21

除了內(nèi)置compile函數(shù),標(biāo)準(zhǔn)庫(kù)里還有py_compile>compileall可供選擇。

?>importpy_compile,compileall

?>py_pile("test.py","test.pyo")

>?Is

main.py*test.pytest.pyo

?>pile_dir(".",0)

Listing

Compiling./main.py..

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論