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