基礎語法
有節(jié)制地使用 from...import 語句
Python 提供三種方式來引入外部模塊:import語句、from...import語句以及import函數(shù)鬼吵,其中import函數(shù)顯式地將模塊的名稱作為字符串傳遞并賦值給命名空間的變量扣甲。
使用import需要注意以下幾點:
優(yōu)先使用import a的形式
有節(jié)制地使用from a import A
盡量避免使用from a import *
為什么呢?我們來看看 Python 的 import 機制齿椅,Python 在初始化運行環(huán)境的時候會預先加載一批內建模塊到內存中琉挖,同時將相關信息存放在sys.modules中,我們可以通過sys.modules.items()查看預加載的模塊信息涣脚,當加載一個模塊時示辈,解釋器實際上完成了如下動作:
在sys.modules中搜索該模塊是否存在,如果存在就導入到當前局部命名空間遣蚀,如果不存在就為其創(chuàng)建一個字典對象矾麻,插入到sys.modules中
加載前確認是否需要對模塊對應的文件進行編譯,如果需要則先進行編譯
執(zhí)行動態(tài)加載芭梯,在當前命名空間中執(zhí)行編譯后的字節(jié)碼险耀,并將其中所有的對象放入模塊對應的字典中
從上可以看出,對于用戶自定義的模塊玖喘,import 機制會創(chuàng)建一個新的 module 將其加入當前的局部命名空間中甩牺,同時在 sys.modules 也加入該模塊的信息,但本質上是在引用同一個對象累奈,通過test.py所在的目錄會多一個字節(jié)碼文件贬派。
優(yōu)先使用 absolute import 來導入模塊
i+=1 不等于 ++i
首先++i或--i在 Python 語法上是合法,但并不是我們通常理解的自增或自減操作:
原來+或-只表示正負數(shù)符號费尽。
使用 with 自動關閉資源
對于打開的資源我們記得關閉它赠群,如文件、數(shù)據(jù)庫連接等旱幼,Python 提供了一種簡單優(yōu)雅的解決方案:with查描。
先來看with實現(xiàn)的原理吧。
with的實現(xiàn)得益于一個稱為上下文管理器(context manager)的東西柏卤,它定義程序運行時需要建立的上下文冬三,處理程序的進入和退出,實現(xiàn)了上下文管理協(xié)議缘缚,即對象中定義了enter()和exit()勾笆,任何實現(xiàn)了上下文協(xié)議的對象都可以稱為一個上下文管理器:
enter():返回運行時上下文相關的對象
exit(exception_type, exception_value, traceback):退出運行時的上下文,處理異常桥滨、清理現(xiàn)場等
with 表達式 [as 目標]:代碼塊
包含with語句的代碼塊執(zhí)行過程如下:
計算表達式的值窝爪,返回一個上下文管理器對象
加載上下文管理器對象的exit()以備后用
調用上下文管理器對象的enter()
將enter()的返回值賦給目標對象
執(zhí)行代碼塊弛车,正常結束調用exit(),其返回值直接忽略蒲每,如果發(fā)生異常纷跛,會調用exit()并將異常類型、值及 traceback 作為參數(shù)傳遞給exit()邀杏,exit()返回值為 false 異常將會重新拋出贫奠,返回值為 true 異常將被掛起,程序繼續(xù)執(zhí)行
于此望蜡,我們可以自定義一個上下文管理器:
Python 還提供contextlib模塊唤崭,通過 Generator 實現(xiàn),其中的 contextmanager 作為裝飾器來提供一種針對函數(shù)級別上的上下文管理器脖律,可以直接作用于函數(shù)/對象而不必關心enter()和exit()的實現(xiàn)谢肾。
使用 else 子句簡化循環(huán)(異常處理)
Python 的 else 子句提供了隱含的對循環(huán)是否由 break 語句引發(fā)循環(huán)結束的判斷,有點繞哈状您,來看例子:
可以看出勒叠,else 子句在循環(huán)正常結束和循環(huán)條件不成立時被執(zhí)行,由 break 語句中斷時不執(zhí)行膏孟,同樣眯分,我們可以利用這顆語法糖作用在 while 和 try...except 中。
遵循異常處理的幾點基本原則
異常處理的幾點原則:
注意異常的粒度柒桑,不推薦在 try 中放入過多的代碼
謹慎使用單獨的 except 語句處理所有異常弊决,最好能定位具體的異常
注意異常捕獲的順序,在適合的層次處理異常魁淳,Python 是按內建異常類的繼承結構處理異常的飘诗,所以推薦的做法是將繼承結構中子類異常在前拋出,父類異常在后拋出
使用更為友好的異常信息界逛,遵守異常參數(shù)的規(guī)范
避免 finally 中可能發(fā)生的陷阱
當 finally 執(zhí)行完畢時昆稿,之前臨時保存的異常將會再次被拋出,但如果 finally 語句中產(chǎn)生了新的異诚荩或執(zhí)行了 return 或 break 語句溉潭,那么臨時保存的異常將會被丟失,從而異常被屏蔽少欺。
在實際開發(fā)中不推薦 finally 中使用 return 語句進行返回喳瓣。
深入理解 None,正確判斷對象是否為空
類型FalseTrue布爾False (與0等價)True (與1等價)字符串""( 空字符串)非空字符串赞别,例如 " ", "blog"數(shù)值0, 0.0非0的數(shù)值畏陕,例如:1, 0.1, -1, 2容器[], (), {}, set()至少有一個元素的容器對象,例如:[0], (None,), ['']NoneNone非None對象
3執(zhí)行中會調用nonzero()來判斷自身對象是否為空并返回0/1或True/False仿滔,如果沒有定義該方法惠毁,Python 將調用len()進行判斷犹芹,返回 0 表示為空。如果一個類既沒有定義len()又沒有定義nonzero()仁讨,該類實例用 if 判斷為True羽莺。
連接字符串優(yōu)先使用 join 而不是 +
這一點之前我在博文里總結過实昨,+涉及到更多的內存操作洞豁。
格式化字符串時盡量使用 .format 而不是 %
同上。
區(qū)別對待可變對象和不可變對象
Python 中一切皆對象荒给,每個對象都有一個唯一的標識符(id)丈挟、類型(type)和值。數(shù)字志电、字符串曙咽、元組屬于不可變對象,字典挑辆、列表例朱、字節(jié)數(shù)組屬于可變對象。
默認參數(shù)在初始化時僅僅被評估一次鱼蝉,以后直接使用第一次評估的結果洒嗤,course 指向的是 list 的地址,每次操作的實際上是 list 所指向的具體列表魁亦,所以對于可變對象的更改會直接影響原對象渔隶。
最好的方法是傳入None作為默認參數(shù),在創(chuàng)建對象的時候動態(tài)生成列表洁奈。
[]间唉、() 和 {} 一致的容器初始化形式
其實就是列表生成式、元組生成式和字典生成式利术。
記住函數(shù)傳參既不是傳值也不是傳引用
正確的說法是傳對象(call by object)或傳對象的引用(call-by-object-reference)呈野,函數(shù)參數(shù)在傳遞過程中將整個對象傳入,對可變對象的修改在函數(shù)外部以及內部都可見印叁,對不可變對象的”修改“往往是通過生成一個新對象然是賦值實現(xiàn)的被冒。
警惕默認參數(shù)潛在的問題
其中就是默認參數(shù)如果是可變對象,在調用者和被調用者之間是共享的喉钢。
慎用變長參數(shù)
- 原因如下:
使用過于靈活姆打,導致函數(shù)簽名不夠清晰,存在多種調用方式
使用args和*kw簡化函數(shù)定義就意味著函數(shù)可以有更好的實現(xiàn)方法
- 使用場景:
為函數(shù)添加一個裝飾器
參數(shù)數(shù)目不確定
實現(xiàn)函數(shù)的多態(tài)或子類需要調用父類的某些方法時
深入理解 str() 和repr() 的區(qū)別
- 總結幾點:
str()面向用戶肠虽,返回用戶友好和可讀性強的字符串類型幔戏;repr()面向 Python 解釋器或開發(fā)人員,返回 Python 解釋器內部的含義
解釋器中輸入a默認調用repr()税课,而print(a)默認調用str()
repr()返回值一般可以用eval()還原對象:obj == eval(repr(obj))
以上兩個方法分別調用內建的str()和repr()闲延,一般來說類中都應該定義repr()痊剖,但當可讀性比準確性更為重要時應該考慮str(),用戶實現(xiàn)repr()方法的時候最好保證其返回值可以用eval()是對象還原
分清 staticmethod 和 classmethod 的適用場景
這兩種方法之前已經(jīng)總結過了的垒玲,下面我們只討論它們的使用場景陆馁。
調用類方法裝飾器的修飾器的方法,會隱式地傳入該對象所對應的類合愈,可以動態(tài)生成對應的類的類變量叮贩,同時如果我們期望根據(jù)不同的類型返回對應的類的實例,類方法才是正確的解決方案佛析。
反觀靜態(tài)方法益老,當我們所定義的方法既不跟特定的實例相關也不跟特定的類相關,可以將其定義為靜態(tài)方法寸莫,這樣使我們的代碼能夠有效地組織起來捺萌,提高可維護性。
當然膘茎,也可以考慮定義一個模塊桃纯,將一組的方法放入其中,通過模塊來訪問披坏。