《Python學(xué)習(xí)手冊(cè)》學(xué)習(xí)總結(jié)
本篇文章是作者關(guān)于在學(xué)習(xí)了《Python學(xué)習(xí)手冊(cè)》以后,分享的學(xué)習(xí)心得,在此之前,我們先給大家分享一下這本書(shū):
下載地址:Python學(xué)習(xí)手冊(cè)第4版
之前為了編寫(xiě)一個(gè)svm分詞的程序而簡(jiǎn)單學(xué)了下Python,覺(jué)得Python很好用,想深入并系統(tǒng)學(xué)習(xí)一下,了解一些機(jī)制,因此開(kāi)始閱讀《Python學(xué)習(xí)手冊(cè)》。 在前兩章節(jié)都是對(duì)基本的信息做了概述,我們從第三章開(kāi)始。
第三章 如何運(yùn)行程序
import進(jìn)行模塊導(dǎo)入只能運(yùn)行一次,多次運(yùn)行需使用reload。
模塊往往是變量名的封裝,被認(rèn)為是命名空間。例如:
#myfile.py title = "test" >>>import myfile >>>print myfile.title test
替代方案是from,下面有同樣的效果:
>>>from myfile import title >>>print tittle test
from myfile import * 則可以把myfile所有變量全部導(dǎo)入(第19章內(nèi)容)。
第四章 介紹Python對(duì)象類(lèi)型
雖然字符串支持多種操作,但是它具有不可變性,即原字符串不能改變,只能用新字符串作為結(jié)果賦予一個(gè)變量。下面是一個(gè)試圖改變?cè)址牟僮骷皥?bào)錯(cuò)信息:
>>> s="spam" >>> s[0] = 'z' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment
第五章 數(shù)字
str和repr顯示格式
>>>num = 1/3.0 >>>num 0.33333333333333331 >>>print num 333333333333 >>>repr(num) '0.33333333333333331' #交互模式回顯 >>>str(num) '333333333333' #打印語(yǔ)句
浮點(diǎn)數(shù)運(yùn)算在精確方面有缺陷。這和硬件有關(guān),打印結(jié)果也不能完全解決。
>>> 0.1+0.1+0.1-0.3 5.551115123125783e-17 >>> print 0.1+0.1+0.1-0.3 5.55111512313e-17
使用小數(shù)對(duì)象可以進(jìn)行修正
>>> from decimal import Decimal >>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3') Decimal('0.0')
第六章 動(dòng)態(tài)類(lèi)型簡(jiǎn)介
a = 3這個(gè)語(yǔ)句實(shí)際上執(zhí)行了三個(gè)步驟:創(chuàng)建一個(gè)對(duì)象代表值3;如果還未創(chuàng)建,創(chuàng)建一個(gè)變量a;將變量與新的對(duì)象3連接。這時(shí),變量a成為了對(duì)象3的一個(gè)引用,也可以看做是指針。
類(lèi)型屬于對(duì)象,而不是變量,這就很好理解為什么Python中同一個(gè)變量名可以作為不同類(lèi)型的對(duì)象的引用了。
在這種機(jī)制下,每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù)器,當(dāng)計(jì)數(shù)器為0時(shí)就被系統(tǒng)回收,這便是Python中對(duì)象的垃圾收集的方法了。
不同變量引用同一個(gè)數(shù)字或字符串時(shí),對(duì)變量操作(eg.a=3 a=a+2)只是創(chuàng)建了一個(gè)新的對(duì)象并使它引用新對(duì)象,這也是上一章提到的字符串不能改動(dòng)的原因。而對(duì)于一些類(lèi)型來(lái)說(shuō),有的操作確實(shí)能改變對(duì)象,如下所示:
#situation 1 >>>L1=[2,3,4] >>>L2=L1 >>>L1=24 >>>L2 [2,3,4] #situation 2 >>L1=[2,3,4] >>>L2=L1 >>>L2[0]=24 >>>L1 [24,3,4]
為了讓兩個(gè)變量使用不同的對(duì)象,可以拷貝對(duì)象,使用L2=L1[:]來(lái)代替L2=L1即可。對(duì)于字典則使用D.copy()方法。標(biāo)準(zhǔn)庫(kù)的copy模塊提供了一個(gè)對(duì)任意對(duì)象的調(diào)用方法,下面兩種方式的區(qū)別暫不討論:
import copy X = copy.copy(Y) #表層拷貝 X = copy.deepcopy(Y) #深拷貝
這里就出現(xiàn)了個(gè)問(wèn)題,兩個(gè)引用是否是同一對(duì)象?可以用下面的方式判斷:
>>>L=[1,2,3] >>>M=L >>>L== M True >>>L is M True
負(fù)值索引相當(dāng)于從末尾倒數(shù)。-1就是最后一個(gè)元素的索引。對(duì)于s="spam",-5是個(gè)非法的索引值。分號(hào):前的空值表示從第一個(gè)開(kāi)始,后的空值表示直到最后一個(gè)。
第七章 字符串
單雙引號(hào)是一樣的,這樣允許用戶(hù)不使用轉(zhuǎn)移字符來(lái)實(shí)現(xiàn)帶有單或雙引號(hào)的字符串。個(gè)人認(rèn)為避免了按shift才能使用雙引號(hào)“的麻煩。
>>>'knight"s ',"knight's" ('knight"s ',"knight's")
此外,合并相鄰的字符串常量,如'knight"s ' "knight's"(中間有空格)會(huì)顯示為'knight"s knight\'s'??梢?jiàn),最外層是單引號(hào),為了保持原內(nèi)容,Python把單引號(hào)里的單引號(hào)改寫(xiě)成了轉(zhuǎn)義字符,這個(gè)例子和書(shū)上的不同,更有助于理解。轉(zhuǎn)義字符和C很類(lèi)似,多了幾種;但是Python里沒(méi)有空字符串,Python為每個(gè)字符串保存了內(nèi)容和長(zhǎng)度。同時(shí),如果一個(gè)字符串中沒(méi)有合法的轉(zhuǎn)義編碼出現(xiàn)在"\"后,那么它將在字符串中保留反斜線。抑制轉(zhuǎn)義的方法是在字符串前加r,如r"C:\new\text.dat",此時(shí)的\n和\t就不會(huì)被當(dāng)做是轉(zhuǎn)義字符,同時(shí),這樣做也不必把\改寫(xiě)成\\。
三重引號(hào)適用于多行的字符串的直接輸入而不使用轉(zhuǎn)義字符。利用三重引號(hào)也可以實(shí)現(xiàn)類(lèi)似C中/* */注釋掉代碼的目的。
Unicode字符串通過(guò)在前面加u獲得。
擴(kuò)展分片是第三個(gè)索引,用作步進(jìn)。這時(shí)完整的分片形式為X[I:J:K],其中步進(jìn)為K。當(dāng)步進(jìn)取-1時(shí),可以把字符串反轉(zhuǎn),很神奇的方法。
利用分片,可以對(duì)字符串進(jìn)行修改,即把新字符串加到原字符串上,再把原字符串切掉。
字符串格式化的用法與C的printf很像,不同之處在于所有參數(shù)外需要加一個(gè)(),形成%(arg1,arg2,arg3)的形式。格式化代碼請(qǐng)參考原書(shū)表格,通用結(jié)構(gòu):%[(name)][flags][width][.precision]code,其中name可以是字典名,這時(shí)在參數(shù)表里提供這個(gè)字典的鍵即可。
既然字符串是對(duì)象,那么它就有對(duì)應(yīng)的方法。書(shū)上介紹了修改字符串的replace()、查找find()、把每個(gè)元素取出創(chuàng)建列表的list()、把列表合并成字符串的join()(可以作為list()的反操作)、提取組件的split()。
第八章 列表
用中括號(hào)表示列表,列表的組成對(duì)象是有序的,組成列表的各個(gè)對(duì)象允許不同。
用大括號(hào)表示字典,字典的組成對(duì)象是無(wú)序的,字典鍵的搜索方式是哈希搜索,速度很快。
可以用字典來(lái)模擬列表:使用序數(shù)作為字典的索引即可。類(lèi)似地,字典可以用來(lái)表示一些稀疏矩陣。
字典的get方法用于避免不存在的鍵,如果鍵不存在,返回值是0。
字典接口是使用方式類(lèi)似字典并且實(shí)際工作都和字典一樣的一些Python擴(kuò)展程序的接口。
第9章 元組、文件及其他
用小括號(hào)表示元組,元組不能原處修改。
為了避免只含一個(gè)元素的元組被當(dāng)做表達(dá)式,使用一個(gè)逗號(hào),寫(xiě)為(40,)。逗號(hào)可以幫助識(shí)別元組,下面的也是元組的表示方式:
t = 0,'Ni',1.2,3
從文件中讀取的是字符串,需要作為其他類(lèi)型來(lái)操作時(shí)必須轉(zhuǎn)換。
eval()用來(lái)把字符串作為對(duì)象,因此也可以達(dá)到執(zhí)行Python的任何表達(dá)式。
pickle模塊可以直接在文件中存儲(chǔ)幾乎任何Python對(duì)象。
struct模塊提供了二進(jìn)制數(shù)據(jù)的打包。打包+存入文件,讀取文件+解包。
在“賦值VS引用”這一節(jié),對(duì)于復(fù)合方式的賦值,修改其成員會(huì)導(dǎo)致所有使用該成員的對(duì)象的改變。直觀來(lái)看就是下面:
>>>X = [1,2,3] >>>L = ['a', X, 'b'] >>>D = {'x':X, 'y':2} >>>X[1] = 'surprise' >>>L ['a', [1,'surprise',3], 'b'] >>>D {'x':[1,'surprise',3], 'y':2}
這是一個(gè)陷阱,為了避免這種情況,根據(jù)具體類(lèi)型使用拷貝(比如分片、copy方法)而不是引用。
Python內(nèi)部暫時(shí)存儲(chǔ)并重復(fù)使用短字符串,因此對(duì)同樣內(nèi)容的字符串,is判定可能根據(jù)其長(zhǎng)度為T(mén)rue(字符串較短時(shí))或False(字符串較長(zhǎng)時(shí))。不同類(lèi)型的比較(用==進(jìn)行)的判定方式不一樣。
還有其他內(nèi)置類(lèi)型陷阱,如重復(fù)能增加層次深度,循環(huán)數(shù)據(jù)結(jié)構(gòu)L=L.append(L)
第二部分練習(xí)題
2.(摘自附錄B)分片運(yùn)算超出邊界(例如,L[-1000:100])可工作,因?yàn)镻ython會(huì)縮放超出邊界的分片(必要時(shí),限制值可設(shè)為零和序列長(zhǎng)度)。以翻轉(zhuǎn)的方式提取序列是行不通的(較低邊界值比較高邊界值更大,例如,L[3:1])。你會(huì)得到空分片([ ]),因?yàn)镻ython會(huì)縮放分片限制值,以確定較低邊界永遠(yuǎn)比較高邊界小或相等(例如,L[3:1]會(huì)縮放成L[3:3],空的插入點(diǎn)是在偏移值3處)。Python分片一定是從左至右抽取,即使你用負(fù)號(hào)索引值也是這樣(會(huì)先加上序列長(zhǎng)度轉(zhuǎn)換成正值)。注意到,Python 2.3的第三限制值分片會(huì)稍微修改此行為:L[3:1:-1]的確是從右至左抽取。
3.索引運(yùn)算、分片運(yùn)算以及del:對(duì)于L=[1,2,3,4], L[2] = []只能把3變?yōu)閇],而L[2:3] = []卻能刪掉第三項(xiàng)。
4.X,Y = Y,X,左邊視為兩個(gè)對(duì)象,右邊視為一個(gè)元組,這個(gè)表達(dá)式交換了兩個(gè)引用。
第10章 Python語(yǔ)句簡(jiǎn)介
絕大多數(shù)的Python程序每行一個(gè)語(yǔ)句,不需要分號(hào)。Python的風(fēng)格就是完全不要分號(hào),雖然在語(yǔ)句末加上分號(hào)也能通過(guò)。唯一需要分號(hào)的情況是一行中多個(gè)語(yǔ)句的分隔符。相反地,括號(hào)可以使一個(gè)語(yǔ)句分隔成很多行,比如用列表直觀地定義一個(gè)矩陣時(shí)。反斜線\也可以達(dá)到這個(gè)目的。
嵌套代碼只需要保持縮進(jìn)一致即可。Python是WYSIWYG語(yǔ)言(what you see is what you get,所見(jiàn)即所得)
第11章 賦值、表達(dá)式和打印
形如X+=Y的賦值語(yǔ)句稱(chēng)為增強(qiáng)賦值語(yǔ)句,它有三個(gè)優(yōu)點(diǎn):程序員輸入減少,左側(cè)只需要計(jì)算一次(X=X+Y中X計(jì)算兩次),優(yōu)化技術(shù)會(huì)自動(dòng)選擇(支持原處修改的類(lèi)型可以直接原處修改)。
單一下劃線開(kāi)頭的變量名不會(huì)被from module import *這樣的語(yǔ)句導(dǎo)入。前后都有雙下劃線的變量名是系統(tǒng)定義的變量名,對(duì)解釋器有特殊意義。雙下劃線開(kāi)頭但結(jié)尾沒(méi)有雙下劃線的變量是類(lèi)的本地變量(參考第19章)。
表達(dá)式語(yǔ)句通常用于執(zhí)行可原處修改列表的列表方法,即對(duì)于列表L,L.append(3)是正確的,而L=L.append(4)是錯(cuò)誤的,第二個(gè)式子右邊返回的是None。
標(biāo)準(zhǔn)輸出的重定向方法:
import sys sys.stdout = open('log.txt','a') ... print x,y,x #寫(xiě)入log.txt
為了避免忘記恢復(fù)sys.stdout,寫(xiě)入log.txt也可以用:
log = open('log.txt','a') print >>log, x, y, x
第12章 if測(cè)試
類(lèi)似于C,Python的布爾運(yùn)算or是短路運(yùn)算,而它返回第一個(gè)為真的操作對(duì)象,或者是第二個(gè)為假的對(duì)象。[ ] or { } 將返回{ }。
if選擇分支有以下幾種等價(jià)形式:
#最常見(jiàn)的分支形式 if X: A = Y else: A = Z #Python2.5以后引入 A = Y if X else Z #Python2.5以前(以后也兼容) #需要理解and和or的運(yùn)算和返回值規(guī)則 A = ((X and Y) or Z) #列表形式 A = [Z,Y][bool(X)]
第13章 while和for循環(huán)
pass語(yǔ)句是無(wú)運(yùn)算的占位符,為了表示語(yǔ)法需要語(yǔ)句并且還沒(méi)有任何實(shí)用的語(yǔ)句可寫(xiě)時(shí)就可以使用它。
while和for循環(huán)都有一個(gè)可選的else語(yǔ)句,在循環(huán)條件不滿(mǎn)足時(shí)且沒(méi)有用break結(jié)束循環(huán)時(shí)使用。
C語(yǔ)言形式的 while((x = next()) != NULL) { ...process x...}在Python里行不通:C語(yǔ)言賦值語(yǔ)句會(huì)返回賦值后的值,而Python賦值語(yǔ)句只是語(yǔ)句,不是表達(dá)式。
Python的迭代協(xié)議:有next方法的對(duì)象會(huì)前進(jìn)到下一個(gè)結(jié)果,而在末尾時(shí)引發(fā)StopIteration。所有的迭代工具內(nèi)部工作都調(diào)用next,并捕捉StopIteration異常來(lái)確定何時(shí)離開(kāi)。
用for修改列表時(shí),for x in L:x+=1是無(wú)法修改的,因?yàn)樗薷牡氖茄h(huán)變量x而不是列表L。應(yīng)該使用L[i] +=1的索引來(lái)控制修改。
zip()可以用于for并行修改多個(gè)對(duì)象時(shí)的情況(按最短的截?cái)啵K部梢杂脕?lái)再循環(huán)中建立列表:for (k,v) in zip(keys, vals):D[k]=v。
enumerate()用于產(chǎn)生偏移和元素:for (offset,item) in enumerate(S): print offset,item
基本的列表解析:L=[x+10 for x in L]
擴(kuò)展的列表解析,刪除文件中的換行符:
lines = [line.rstrip() for line in open('script1.py') if line[0] =='p']
從文件中逐行讀取文本行的最佳方法是不要刻意去讀:
for line in open('script1.py'): print line.upper()
第十四章 文檔
__doc__屬性封裝了對(duì)象上的文檔,通過(guò)它可以查看(比如函數(shù)的)注釋。
文檔字符串被認(rèn)為最是用于較大、功能性的文檔,而#最好只限于關(guān)于費(fèi)解的表達(dá)式或語(yǔ)句的微型文檔。PyDoc系統(tǒng)能夠?qū)⑶罢呷〕霾@示。
第十五章 函數(shù)基礎(chǔ)
def是可執(zhí)行代碼,直到運(yùn)行了def時(shí)其定義的函數(shù)才開(kāi)始存在。
由于函數(shù)的參數(shù)沒(méi)有類(lèi)型規(guī)定,因此可以很方便地實(shí)現(xiàn)多態(tài):
>>>def times(x,y): ... return x*y ... >>>times(2,4) 8 >>>times('Ni',4) 'NiNiNiNi'
第十六章 作用域與參數(shù)
變量名解析的LEGB原則:變量名引用分為三個(gè)作用域進(jìn)行查找,本地作用域(L,每次調(diào)用函數(shù)時(shí)創(chuàng)建)、上一級(jí)調(diào)用的本地作用域(E)、全局作用域(G,模塊作用域)、內(nèi)置作用域(B,預(yù)定義的變量名如open)。僅對(duì)簡(jiǎn)單變量生效,對(duì)于特定對(duì)象的變量如object.spam,查找規(guī)則規(guī)則完全不同。
內(nèi)置作用域是一個(gè)名為_(kāi)_builtin__的內(nèi)置模塊,import后才可以使用,這時(shí)可以用dir(__buildin__)查看預(yù)定義的變量名。根據(jù)LEGB原則,在本地作用域定義一個(gè)新的open = 'spam'會(huì)導(dǎo)致open()函數(shù)不能被調(diào)用。
global用于全局變量聲明。
作者認(rèn)為在模塊導(dǎo)入時(shí),導(dǎo)入其他模塊的模塊擁有了對(duì)其他模塊變量的修改權(quán),這使得被導(dǎo)入模塊的維護(hù)變得復(fù)雜:維護(hù)者不知道第二個(gè)模塊什么情況下會(huì)修改變量。因此最好的解決辦法是不這樣做,在文件間進(jìn)行通信的最好辦法就是通過(guò)調(diào)用函數(shù),傳遞參數(shù),然后獲得返回值(用函數(shù)提供修改變量的接口,并且告訴維護(hù)者這個(gè)變量可以被其他模塊改變)。
工廠函數(shù)(又稱(chēng)閉合),是能記住嵌套作用域的變量值的函數(shù)。示例:
>>> def maker(N): ... def action(X): ... return X ** N ... return action ... >>> f = maker(2) >>> f #顯示f的引用 <function action at 0xb7738294> >>> f(3) 9 >>> f(4) 16 >>> g = maker(3) >>> g(3) 27 >>> f(3) 9
對(duì)于函數(shù)參數(shù),不可變參數(shù)是通過(guò)傳值來(lái)傳遞,可變對(duì)象(列表、字典等)是通過(guò)傳引用進(jìn)行傳遞的。
多個(gè)返回值的常用return方式是使用元組。
函數(shù)參數(shù)的四種匹配方式:位置匹配、關(guān)鍵字參數(shù)、所有對(duì)象、所有關(guān)鍵字/值:
>>>def f(a,b,c):print a,b,c #常規(guī)匹配 >>>f(1,2,3) 1 2 3 >>>f(c=3,b=2,a=1) #關(guān)鍵字匹配 1 2 3 >>>f(1,c=3,b=2) #位置+關(guān)鍵字匹配 1 2 3 >>>def f(a,b=2,c=3):print a,b,c #默認(rèn)參數(shù) >>>f(1) 1 2 3 >>>f(a=1) 1 2 3 >>>def f(*args):print args # 任意參數(shù)* >>>f() () >>>f(1) (1,) >>>f(1,2,3,4) >>>def f(**args):print args # 任意參數(shù)**,把參數(shù)組裝成為字典 >>>f() {} >>>f(a=1,b=2) {'a'=1,'b'=2}
相反地,調(diào)用函數(shù)在參數(shù)變量前面加*可以分解參數(shù)。
參數(shù)匹配順序:調(diào)用和定義中先是非關(guān)鍵字參數(shù)(name)、然后是關(guān)鍵字參數(shù)(name=value)、*name最后是**name。
第17章 函數(shù)的高級(jí)話題
def f(x,y,z):return x+y+z和f= lambda x,y,z:x+y+z會(huì)達(dá)到同樣的效果。lambda是一個(gè)表達(dá)式,而不是語(yǔ)句,允許出現(xiàn)在def不能出現(xiàn)的地方。正是因?yàn)檫@個(gè)特點(diǎn),lambda比def的使用更加靈活,比如編寫(xiě)跳轉(zhuǎn)表(也即行為的列表或字典):L=[(lambda x:x**2),[(lambda x:x**3),[(lambda x:x**4)]。出于代碼易讀性的考慮,應(yīng)盡量避免嵌套的lambda。
apply的介紹略過(guò),它可以用*和**型參數(shù)代替。(似乎在Python3.0以上版本已廢棄,待確認(rèn))
map(func,arg)可以很方便的用函數(shù)func處理列表類(lèi)型的數(shù)據(jù),而自己編寫(xiě)類(lèi)似的功能需要使用for來(lái)完成。
filter和reduce這兩個(gè)函數(shù)工具分別用于列表過(guò)濾和列表全元素的逐個(gè)運(yùn)算。
關(guān)于列表解析,帶if條件的之前已提過(guò),不再重復(fù)。for的應(yīng)用示例:
>>> res = [x+y for x in [0,1,2] for y in [100,200,300]] >>> res [100, 200, 300, 101, 201, 301, 102, 202, 302]
更進(jìn)一步的嵌套:
>>>[(x,y) for x in range(5) if x%2 ==0 for y in range(5) if y%2==0]
作者在這里開(kāi)了個(gè)小玩笑:“而map和filter的等效形式往往更復(fù)雜也會(huì)有深層的嵌套,這里不進(jìn)行說(shuō)明,將這部分代碼留給禪師、前LISP程序員以及犯罪神經(jīng)病作為練習(xí)”。
生成器函數(shù)與一般函數(shù)不同之處在于,它yield而不是return一個(gè)值,并把自己掛起,現(xiàn)場(chǎng)保存在下一次調(diào)用。為與列表解析相區(qū)分,可以使用圓括號(hào)作為生成器表達(dá)式:
>>> for num in (x **2 for x in range(4)): ... print '%s,%s' %(num,num/2.0) ... 0,0.0 1,0.5 4,2.0 9,4.5
一個(gè)測(cè)試不同的迭代方法的小程序。當(dāng)然,對(duì)于不同的操作,不同方法的相對(duì)速度可能不一樣,不存在所有情況下都最快的“最優(yōu)方法”:
#file timerseqs.py import time,sys reps = 1000 size = 10000 def tester(func, *args): startTime = time.time() for i in range(reps): func(*args) elapsed = time.time() - startTime return elapsed def forStatement(): res = [] for x in range(size): res.append(abs(x)) def listComprehension(): res = [abs(x) for x in range(size)] def mapFunction(): res = map(abs, range(size)) def generatorExpression(): res = list(abs(x) for x in range(size)) print sys.version tests = (forStatement, listComprehension, mapFunction,generatorExpression) for testfunc in tests: print testfunc.__name__.ljust(20), '=>',tester(testfunc)
陷阱:本地變量是靜態(tài)檢測(cè)的。這意味著如果在模塊里定義了X=99,def一個(gè)函數(shù)print X后又在函數(shù)里X=88,那么就會(huì)報(bào)錯(cuò)。
陷阱:默認(rèn)對(duì)象在def時(shí)賦值,而不是調(diào)用函數(shù)時(shí)賦值。
第18章 模塊:宏偉藍(lán)圖
Python進(jìn)行import時(shí)搜索目錄的順序:主目錄、PYTHONPATH環(huán)境變量目錄、標(biāo)準(zhǔn)庫(kù)目錄、.pth目錄。
第19章 模塊代碼編寫(xiě)基礎(chǔ)
將會(huì)被用于導(dǎo)入的模塊文件命名需要以.py做結(jié)尾。
當(dāng)兩個(gè)不同模塊使用了相同的變量名時(shí),不能用from,只能用import。
(本章大部分內(nèi)容都在第三章介紹過(guò))
第20章 模塊包
import時(shí)列出路徑名稱(chēng),以點(diǎn)號(hào)相隔:import dir1.dir2.mod。這與平臺(tái)無(wú)關(guān),import不能使用平臺(tái)特定的路徑表達(dá)方式。同時(shí),這也表明文件名省略了.py的原因。另外,dir1和dir2中必須包含一個(gè)__init__.py文件(可以為空,Python首次進(jìn)入其所在目錄時(shí)會(huì)執(zhí)行它的內(nèi)容)。每次使用路徑必須完整輸入,使用import dir1.dir2.mod as mod中定義的mod代替前面過(guò)長(zhǎng)的路徑名可以解決這個(gè)問(wèn)題。
個(gè)人認(rèn)為,模塊包是為了方便同名模塊的使用不發(fā)生混淆的方式,這是軟件開(kāi)發(fā)時(shí)所需要的。
第21章 高級(jí)模塊話題
_X的命名方式可以防止from *導(dǎo)入這個(gè)變量,然而這種方法不能阻止其他導(dǎo)入方式的導(dǎo)入,并不是一些面向?qū)ο笳Z(yǔ)言中的私有聲明。
__all__會(huì)列出from *復(fù)制的變量名,與_X正相反。同樣只對(duì)from *有效,不是私有聲明。
from __feature__ import featurename還不是很理解,好象是用選用擴(kuò)展功能的方式開(kāi)啟特殊的代碼編譯。
模塊可以通過(guò)檢測(cè)自己的__name__是否為"__main__"確定它是在執(zhí)行還是被導(dǎo)入。這樣可以讓模塊在扮演兩種不同角色時(shí)發(fā)揮不同功能。
相對(duì)導(dǎo)入:路徑以一個(gè)點(diǎn)開(kāi)始,定位同一個(gè)包的模塊??梢蚤_(kāi)啟__feature__中強(qiáng)迫導(dǎo)入的絕對(duì)性。很類(lèi)似于Linux,兩個(gè)點(diǎn)表示上一級(jí)路徑。
陷阱一:頂層代碼的語(yǔ)句次序。被import時(shí)模塊的頂層代碼會(huì)立即執(zhí)行,此時(shí)它所引用后文定義的變量將無(wú)效。
陷阱二:字符串變量是不能直接用于import語(yǔ)句的??梢允褂胑xec "import" + modname來(lái)使用字符串modname。這樣做仍然有個(gè)缺點(diǎn),每次執(zhí)行時(shí)必須編譯import語(yǔ)句。更好的代替方案是string = __import__(modname),然后把string單列一行執(zhí)行即可。
陷阱三:from復(fù)制變量名而不是拷貝。
#nested1.py X = 99 def printer():print X #nested2.py from nested1 import X,printer X = 88 printer() %python nested2.py 99
陷阱四:reload不影響from導(dǎo)入。為了更新變量,使用.運(yùn)算符來(lái)導(dǎo)入和修改其他模塊的變量。
陷阱五:reload、from及交互模式測(cè)試。這部分比較有啟發(fā)性,建議在原書(shū)仔細(xì)閱讀,簡(jiǎn)要概括就還是:導(dǎo)入后(模塊)要重載(模塊),重載后還要重新執(zhí)行import(變量)。reload和from的合作并不完美,最佳原則是使用reload和import來(lái)啟動(dòng)程序。
陷阱六:重載沒(méi)有傳遞性。重載A不會(huì)重載A中import的B和C。需要這種功能時(shí)可以自己編寫(xiě)一個(gè)通用工具。
import types def status(module): print 'reloading',module.__name__ def transitive_reload(module,visited): if not visited.has_key(module): status(module) reload(module) visited[module] = None for attrobj in module.__dict__.values(): #For all attrs if type(sttrobj) == types.ModuleType: transitive_reload(attrobj,visited) def reload_all(*args): visited = {} for arg in args: if type(arg) == types.Module Type: transitive_reload(arg,visited) if __name__ == '__main__': import reloadall reload_all(reloadall)
第22章 OOP:宏偉藍(lán)圖
屬性通常是在class語(yǔ)句中通過(guò)賦值語(yǔ)句添加在類(lèi)中,而不是在定義類(lèi)時(shí)嵌入。因此對(duì)沒(méi)有賦值的對(duì)象屬性的訪問(wèn)會(huì)出錯(cuò)。
類(lèi)方法函數(shù)第一個(gè)參數(shù)通常為self(調(diào)用時(shí)不指明),但不一定叫self,位置是關(guān)鍵(來(lái)自習(xí)題5)。作為類(lèi)方法直接調(diào)用時(shí),需指明實(shí)例的名稱(chēng)(24章)。
Python的OOP模型其實(shí)就是在對(duì)象樹(shù)中搜索屬性。
(筆者有部分OOP基礎(chǔ),因此本章具體理論和理解略去)
第23章 類(lèi)代碼編寫(xiě)基礎(chǔ)
類(lèi)其實(shí)也是一種對(duì)象。
在類(lèi)定義外創(chuàng)建的函數(shù)也可以成為方法:
>>>def upperName(self): ... return self.name.upper() >>>rec.method = upperName
第24章 類(lèi)代碼編寫(xiě)細(xì)節(jié)
和def一樣,class也是可執(zhí)行代碼,運(yùn)行時(shí)才會(huì)產(chǎn)生類(lèi)對(duì)象。
調(diào)用超類(lèi)的構(gòu)造器是可以的,在子類(lèi)的構(gòu)造方法中使用Super.__init__()即可。
抽象超類(lèi)有的方法沒(méi)有提供實(shí)現(xiàn),而是由子類(lèi)提供。
類(lèi)的運(yùn)算符重載通過(guò)修改諸如__add__(對(duì)應(yīng)于+)等方法來(lái)實(shí)現(xiàn)。具體細(xì)節(jié)請(qǐng)參考原書(shū)。下面是一個(gè)修改__iter__獲得用戶(hù)定義的迭代器的例子:
class Squares: def __init__(self,start,stop): self.value = start - 1 self.stop = stop def __iter__(self): return self def next(self): if self.value == self.stop: raise StopIteration self.value += 1 return self.value ** 2 %python >>>from iters import Squares >>>for i in Squares(1,5): ... print i, ... 1 4 9 16 25
右側(cè)方法如__radd__中,self在右側(cè),和__add__相反。
__call__可以攔截調(diào)用,用使用函數(shù)的方法使用類(lèi)。對(duì)改寫(xiě)了__call__的類(lèi)prod,實(shí)例化x = prod(2),x(3)可以直接使用。
__del__是析構(gòu)器,但在Python中很少使用析構(gòu)方法。
命名空間其實(shí)是普通的字典。
第25章 類(lèi)的設(shè)計(jì)
無(wú)綁定類(lèi)方法對(duì)象無(wú)self必須明確提供實(shí)例對(duì)象做第一個(gè)參數(shù),綁定實(shí)例方法對(duì)象用self+函數(shù)對(duì),不用傳遞實(shí)例。
委托是指把對(duì)象包裝在代理類(lèi)中。
#trace.py class wrapper: def __init__(self,object): self.wrapped = object def __getattr__(self,attrname): print 'Trace:',attrname return getattr(self.wrapped,attrname) >>>from trace import wrapper >>>x = wrapper([1,2,3]) >>>x.append(4) Trace:append >>>x.wrapped [1,2,3,4]
組合是一種技術(shù),讓控制器類(lèi)嵌入和引導(dǎo)一群對(duì)象,并自行提供接口。
(這一章主要內(nèi)容是幫助讀者從面向過(guò)程向面向?qū)ο筮^(guò)渡,而且比較淺顯,在這方面作者推薦繼續(xù)去讀設(shè)計(jì)模式的書(shū)效果會(huì)更好,這里就不詳細(xì)介紹了)
第26章 類(lèi)的高級(jí)主題
偽私有屬性:將開(kāi)頭兩個(gè)下劃線的變量名前再加上_類(lèi)名。仍然不是真正的私有。
新式類(lèi)從內(nèi)置類(lèi)型創(chuàng)建子類(lèi),或者直接用object作為超類(lèi)。3.0以后所有類(lèi)自動(dòng)成為新式類(lèi)。鉆石繼承在新式類(lèi)里從括號(hào)最右開(kāi)始搜索,這與經(jīng)典類(lèi)正相反。為了解決繼承不同類(lèi)同名變量沖突,可以進(jìn)行強(qiáng)制規(guī)定,如attr = B.attr。
__slots__用來(lái)限制類(lèi)的實(shí)例能有的合法屬性集。
內(nèi)容屬性使用攔截的方式來(lái)提供屬性,但是它本身不是成員變量。類(lèi)似于改寫(xiě)__getattr__,使用property()進(jìn)行。
靜態(tài)方法和類(lèi)方法分別需要調(diào)用staticmethod和classmethod兩個(gè)函數(shù),前者調(diào)用不需要實(shí)例(實(shí)例調(diào)用時(shí)),后者把類(lèi)傳入類(lèi)方法第一個(gè)參數(shù)。
函數(shù)裝飾器在def上一行用@標(biāo)明,有點(diǎn)像包裹函數(shù),@A @B @C后def f()相當(dāng)于f=A(B(C(f)))。
第27章 異?;A(chǔ)
try/except可以用于捕捉異常并從異常中恢復(fù),而try/final可以保證無(wú)論是否發(fā)生異常,終止行為都一定會(huì)進(jìn)行。二者也可以合并使用(2.5版以后)。else在不發(fā)生異常時(shí)執(zhí)行。except有幾種分句形式(請(qǐng)參考原書(shū))。
rasie、assert用于觸發(fā)異常。raise后不帶參數(shù)表示重新引發(fā)當(dāng)前異常(第28章)。
with/as可以用作try/final的替代方案。as后面是with后表達(dá)式的賦值對(duì)象。
第28章 異常對(duì)象
字符串異常(myexc = "My exception string";raise myexc)已經(jīng)在3.0以后消失,現(xiàn)在常用的是基于類(lèi)的異常。類(lèi)異常比字符串異常方便之處在于,可以在原始版本中用超類(lèi)定義異常,在后續(xù)版本中使用子類(lèi)來(lái)描述新的異常,這為版本維護(hù)提供了極大的方便。字符串異常的判斷方式是is而不是==(常見(jiàn)陷阱,29章)。
第29章 異常的設(shè)計(jì)
嵌套的try,引發(fā)異常時(shí)except會(huì)回到先前進(jìn)入但未離開(kāi)的try,而finally不會(huì)停止傳遞。
用try進(jìn)行調(diào)試的方式,在錯(cuò)誤發(fā)生時(shí)程序仍處于激活狀態(tài),可以進(jìn)行其他的測(cè)試而不是重新開(kāi)始:
try: ...run program... except: import sys print 'uncaught!', sys.exc_info()[0], sys.exc_info()[1]
#sys.exc_info有專(zhuān)門(mén)一小節(jié)講解,無(wú)異常返回3個(gè)None
#反之返回type value tracebck
相關(guān)文章
Python變量及數(shù)據(jù)類(lèi)型用法原理匯總
這篇文章主要介紹了Python變量及數(shù)據(jù)類(lèi)型用法原理匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08python?OpenCV實(shí)現(xiàn)圖像特征匹配示例詳解
這篇文章主要為大家介紹了python?OpenCV實(shí)現(xiàn)圖像特征匹配示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04python項(xiàng)目打包成exe和安裝包的方法步驟
本文主要介紹了python項(xiàng)目打包成exe和安裝包的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03python 讀取文件并把矩陣轉(zhuǎn)成numpy的兩種方法
今天小編就為大家分享一篇python 讀取文件并把矩陣轉(zhuǎn)成numpy的兩種方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02Python3爬蟲(chóng)里關(guān)于Splash負(fù)載均衡配置詳解
在本篇文章里小編給大家分享了關(guān)于Python3爬蟲(chóng)里關(guān)于Splash負(fù)載均衡配置的相關(guān)內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。2020-07-07Keras保存模型并載入模型繼續(xù)訓(xùn)練的實(shí)現(xiàn)
這篇文章主要介紹了Keras保存模型并載入模型繼續(xù)訓(xùn)練的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02OpenCV+python實(shí)現(xiàn)實(shí)時(shí)目標(biāo)檢測(cè)功能
這篇文章主要介紹了OpenCV+python實(shí)現(xiàn)實(shí)時(shí)目標(biāo)檢測(cè)功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06一個(gè)非常簡(jiǎn)單好用的Python圖形界面庫(kù)(PysimpleGUI)
這篇文章主要介紹了一個(gè)非常簡(jiǎn)單好用的Python圖形界面庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Python?頁(yè)面解析Beautiful?Soup庫(kù)的使用方法
Beautiful?Soup?簡(jiǎn)稱(chēng)?BS4(其中?4?表示版本號(hào))是一個(gè)?Python?中常用的頁(yè)面解析庫(kù),它可以從?HTML?或?XML?文檔中快速地提取指定的數(shù)據(jù),這篇文章主要介紹了springboot?集成?docsify?實(shí)現(xiàn)隨身文檔?,需要的朋友可以參考下2022-09-09