若想技術(shù)精進离熏,當然得把基礎(chǔ)知識打得牢牢的。
廖雪峰的官方網(wǎng)站 ?python3教程戴涝,該網(wǎng)站提供的教程淺顯易懂滋戳,還附帶了講學(xué)視頻,非常適合初學(xué)者正規(guī)入門啥刻。
以下是通過廖雪峰python官方網(wǎng)站學(xué)習(xí)的個人查漏補缺奸鸯。
主要內(nèi)容包括:(面向?qū)ο蟾呒壘幊? 和 (錯誤、調(diào)試可帽、測試)
?1.__slots__()能夠限制實例屬性 ? ?2.@property裝飾器能夠?qū)㈩惖姆椒ó斪鰧傩哉{(diào)用 ? ?3.多重繼承 ? ?4.定制類(__str__()府喳、__iter__()、__getitem__()蘑拯、__getattr__()钝满、__call__())具體用處請仔細看 ?5.使用枚舉類/使用元類 ? ?6.錯誤處理:try...excpet...finally... ? ?7.調(diào)試 logging才是最好的方式 ? ?8.單元測試 ? ?9.文檔測試
1.面向?qū)ο蟾呒壘幊?/h1>
數(shù)據(jù)封裝兜粘、繼承和多態(tài)只是面向?qū)ο蟪绦蛟O(shè)計中最基礎(chǔ)的3個概念。在Python中弯蚜,面向?qū)ο筮€有很多高級特性孔轴。
1.使用__slots__:限制實例屬性
正常情況下,當我們定義了一個class碎捺,創(chuàng)建了一個class的實例后路鹰,我們可以給該實例綁定任何屬性和方法,這就是動態(tài)語言的靈活性收厨。
但是晋柱,給一個實例綁定的方法,對另一個實例是不起作用的诵叁。為了給所有實例都綁定方法雁竞,可以給class綁定方法,給class綁定方法后拧额,所有實例均可調(diào)用:
通常情況下,上面的set_score方法可以直接定義在class中侥锦,但動態(tài)綁定允許我們在程序運行的過程中動態(tài)給class加上功能进栽,這在靜態(tài)語言中很難實現(xiàn)。
使用__slots__可以限制實例的屬性恭垦,比如快毛,只允許對Student實例添加name和age屬性。為了達到限制的目的番挺,Python允許在定義class的時候唠帝,定義一個特殊的__slots__變量,來限制該class實例能添加的屬性:
除非在子類中也定義__slots__,這樣禁荸,子類實例允許定義的屬性就是自身的__slots__加上父類的__slots__右蒲。
2.使用@property:Python內(nèi)置的@property裝飾器就是負責(zé)把一個方法變成屬性調(diào)用。
把一個getter方法變成屬性赶熟,只需要加上@property就可以了瑰妄,此時,@property本身又創(chuàng)建了另一個裝飾器@score.setter映砖,負責(zé)把一個setter方法變成屬性賦值间坐,于是,我們就擁有一個可控的屬性操作:
@property廣泛應(yīng)用在類的定義中竹宋,可以讓調(diào)用者寫出簡短的代碼劳澄,同時保證對參數(shù)進行必要的檢查,這樣蜈七,程序運行時就減少了出錯的可能性秒拔。
3.多重繼承
MixIn:MixIn的目的就是給一個類增加多個功能砂缩,這樣,在設(shè)計類的時候三娩,我們優(yōu)先考慮通過多重繼承來組合多個MixIn的功能庵芭,而不是設(shè)計多層次的復(fù)雜的繼承關(guān)系。我們不需要復(fù)雜而龐大的繼承鏈雀监,只要選擇組合不同的類的功能双吆,就可以快速構(gòu)造出所需的子類。
由于Python允許使用多重繼承回官,因此,MixIn就是一種常見的設(shè)計搂橙。只允許單一繼承的語言(如Java)不能使用MixIn的設(shè)計歉提。
4.定制類
看到類似__slots__這種形如__xxx__的變量或者函數(shù)名就要注意,這些在Python中是有特殊用途的区转。
1)__str__():返回用戶看到的字符串,而__repr__()返回程序開發(fā)者看到的字符串废离,也就是說侄泽,__repr__()是為調(diào)試服務(wù)的。
2)__iter__:如果一個類想被用于for ... in循環(huán)蜻韭,類似list或tuple那樣悼尾,就必須實現(xiàn)一個__iter__()方法,該方法返回一個迭代對象肖方,然后闺魏,Python的for循環(huán)就會不斷調(diào)用該迭代對象的__next__()方法拿到循環(huán)的下一個值,直到遇到StopIteration錯誤時退出循環(huán)俯画。
3)__getitem__:讓類使用起來更像list或tuple。
與之對應(yīng)的是__setitem__()方法,把對象視作list或dict來對集合賦值泡仗。最后埋虹,還有一個__delitem__()方法,用于刪除某個元素娩怎《至耄總之,通過上面的方法峦树,我們自己定義的類表現(xiàn)得和Python自帶的list辣辫、tuple、dict沒什么區(qū)別魁巩,這完全歸功于動態(tài)語言的“鴨子類型”急灭,不需要強制繼承某個接口。
4)__getattr__:當查找屬性不存在時谷遂,python系統(tǒng)會自動調(diào)用__getattr__()方法葬馋。一個__getattr__()方法,動態(tài)返回一個屬性肾扰。
當調(diào)用不存在的屬性時蒋院,比如score,Python解釋器會試圖調(diào)用__getattr__(self, 'score')來嘗試獲得屬性莲绰,這樣欺旧,我們就有機會返回score的值。 ?注:__getattr__在API動態(tài)調(diào)用上會非常有幫助蛤签。
5)__call__:任何類辞友,只需要定義一個__call__()方法,就可以直接對實例進行調(diào)用震肮。
更多的時候称龙,我們需要判斷一個對象是否能被調(diào)用,能被調(diào)用的對象就是一個Callable對象钙蒙,比如函數(shù)和我們上面定義的帶有__call__()的類實例:
Python的class允許定義許多定制方法躬厌,可以讓我們非常方便地生成特定的類马昨。
5.使用枚舉類/使用元類
更好的方法是為這樣的枚舉類型定義一個class類型竞帽,然后,每個常量都是class的一個唯一實例鸿捧。Python提供了Enum類來實現(xiàn)這個功能屹篓。
6.錯誤處理:try...excpet...finally...
當我們認為某些代碼可能會出錯時,就可以用try來運行這段代碼匙奴,如果執(zhí)行出錯堆巧,則后續(xù)代碼不會繼續(xù)執(zhí)行,而是直接跳轉(zhuǎn)至錯誤處理代碼泼菌,即except語句塊谍肤,執(zhí)行完except后,如果有finally語句塊哗伯,則執(zhí)行finally語句塊荒揣,至此,執(zhí)行完畢焊刹。
調(diào)用棧:如果錯誤沒有被捕獲括丁,它就會一直往上拋睦尽,最后被Python解釋器捕獲,打印一個錯誤信息袱饭,然后程序退出迹淌。
記錄錯誤:Python內(nèi)置的logging模塊可以非常容易地記錄錯誤信息画切。如果不捕獲錯誤东涡,自然可以讓Python解釋器來打印出錯誤堆棧隆嗅,但程序也被結(jié)束了。既然我們能捕獲錯誤敞嗡,就可以把錯誤堆棧打印出來颁糟,然后分析錯誤原因航背,同時喉悴,讓程序繼續(xù)執(zhí)行下去。
同樣是出錯玖媚,但程序打印完錯誤信息后會繼續(xù)執(zhí)行箕肃,并正常退出:
拋出錯誤:用raise語句拋出一個錯誤。
捕獲錯誤目的只是記錄一下今魔,便于后續(xù)追蹤勺像。
7.調(diào)試 ? ? ? ? ? ? ---logging才是終極武器
1)用print()方法,簡單粗暴的方式調(diào)試
2)使用斷言assert調(diào)試错森,assert斷言比print()容易關(guān)閉吟宦。啟動Python解釋器時可以用-O參數(shù)來關(guān)閉assert。
3)使用logging調(diào)試
把print()替換為logging是第3種方式,和assert比,logging不會拋出錯誤蜗侈,而且可以輸出到文件:
logging.info()可以輸出一段文本篷牌。logging的另一個好處是通過簡單的配置,一條語句可以同時輸出到不同的地方踏幻,比如console和文件枷颊。
4)使用pdb調(diào)試-------是一種方法,但是調(diào)試不是很方便
第4種方式是啟動Python的調(diào)試器pdb该面,讓程序以單步方式運行夭苗,可以隨時查看運行狀態(tài)。
python -m pdb python程序文件名
(Pdb) l ?# 輸入命令字母l來查看代碼
(Pdb) n ?# 輸入命令n可以單步執(zhí)行代碼
(Pdb) p 變量名 # 任何時候都可以輸入命令p 變量名來查看變量
(Pdb) q # 輸入命令q結(jié)束調(diào)試隔缀,退出程序
這種通過pdb在命令行調(diào)試的方法理論上是萬能的听诸,但實在是太麻煩了,如果有一千行代碼蚕泽,要運行到第999行得敲多少命令啊晌梨。還好,我們還有另一種調(diào)試方法须妻。
5)pdb.set_trace()方法調(diào)試
pdb.set_trace()-----不是單步執(zhí)行仔蝌,這個方式比直接啟動pdb單步調(diào)試效率要高很多,但也高不到哪去荒吏。
6)IDE
如果要比較爽地設(shè)置斷點敛惊、單步執(zhí)行,就需要一個支持調(diào)試功能的IDE绰更。目前比較好的Python IDE有:
Visual Studio Code:https://code.visualstudio.com/瞧挤,需要安裝Python插件。 ? ? (用過一小段時間)
PyCharm:http://www.jetbrains.com/pycharm/? ?(本電腦上正在使用)
另外儡湾,Eclipse加上pydev插件也可以調(diào)試Python程序特恬。
關(guān)于調(diào)試的各種方法對比,logging才是終極武器徐钠。
8.單元測試 ?---測試驅(qū)動開發(fā)
“測試驅(qū)動開發(fā)”(TDD:Test-Driven Development)癌刽。單元測試:是用來對一個模塊、一個函數(shù)或者一個類來進行正確性檢驗的測試工作尝丐。
這種以測試為驅(qū)動的開發(fā)模式最大的好處就是確保一個程序模塊的行為符合我們設(shè)計的測試用例。在將來修改的時候爹袁,可以極大程度地保證該模塊行為仍然是正確的远荠。
為了編寫單元測試,我們需要引入Python自帶的unittest模塊失息。編寫單元測試時譬淳,我們需要編寫一個測試類乏屯,從unittest.TestCase繼承。以test開頭的方法就是測試方法瘦赫,不以test開頭的方法不被認為是測試方法辰晕,測試的時候不會被執(zhí)行。對每一類測試都需要編寫一個test_xxx()方法确虱。由于unittest.TestCase提供了很多內(nèi)置的條件判斷含友,我們只需要調(diào)用這些方法就可以斷言輸出是否是我們所期望的。最常用的斷言就是assertEqual()校辩。
self.assertEqual(abs(-1), 1) # 斷言函數(shù)返回的結(jié)果與1相等
setUp與tearDown
可以在單元測試中編寫兩個特殊的setUp()和tearDown()方法窘问。這兩個方法會分別在每調(diào)用一個測試方法的前后分別被執(zhí)行。
setUp()和tearDown()方法有什么用呢宜咒?設(shè)想你的測試需要啟動一個數(shù)據(jù)庫惠赫,這時,就可以在setUp()方法中連接數(shù)據(jù)庫故黑,在tearDown()方法中關(guān)閉數(shù)據(jù)庫儿咱,這樣,不必在每個測試方法中重復(fù)相同的代碼:
class TestDict(unittest.TestCase):
????def setUp(self):
????????print('setUp...')
????def tearDown(self):
????????print('tearDown...')
單元測試可以有效地測試某個程序模塊的行為场晶,是未來重構(gòu)代碼的信心保證混埠。
單元測試的測試用例要覆蓋常用的輸入組合、邊界條件和異常诗轻。
單元測試代碼要非常簡單钳宪,如果測試代碼太復(fù)雜,那么測試代碼本身就可能有bug扳炬。
單元測試通過了并不意味著程序就沒有bug了吏颖,但是不通過程序肯定有bug。
9.文檔測試
Python內(nèi)置的“文檔測試”(doctest)模塊可以直接提取注釋中的代碼并執(zhí)行測試恨樟。
doctest非常有用半醉,不但可以用來測試,還可以直接作為示例代碼厌杜。通過某些文檔生成工具奉呛,就可以自動把包含doctest的注釋提取出來。用戶看文檔的時候夯尽,同時也看到了doctest。