本系列文章爲《編寫高質量代碼——改善Python程序的91個建議》的精華彙總。python
Python的3種引入外部模塊的方式:import
語句、from ... import ...
和 __import__
函數。其中前兩種比較常見。算法
在使用 import
時,應注意:數組
import A
或 import A as a
from A import B
from A import *
對於 from a import ...
,若是無節制的使用,會帶來的問題:函數
i += 1
不等於 ++i
Python 解釋器會將 ++i
解釋爲 +(+i)
,其中 +
表示正數符號。對於 --i
也是相似。測試
所以,要明白 ++i
在 Python 的語法層面上是合法的,但並非一般意義上的自增操做。this
with
自動關閉資源對文件操做完成後,應該當即關閉它們,由於打開的文件不只會佔用系統資源,並且可能影響其餘程序或者進程的操做,甚至會致使用戶指望與實際操做結果不一致。debug
Python 提供了 with 語句,語法爲:code
with 表達式 [as 目標]: 代碼塊
with 語句支持嵌套,支持多個 with 子句,它們二者能夠相互轉換。with expr1 as e1, expr2 as e2
與下面的嵌套形式等價:orm
with expr1 as e1: with expr2 as e2:
else
子句簡化循環(異常處理)在循環中, else
子句提供了隱含的對循環是否由 break
語句引起循環結束的判斷。例子:對象
# 如下兩段代碼等價 # 藉助了一個標誌量 found 來判斷循環結束是否是由 break 語句引發的。 def print_prime(n): for i in range(2, n): found = True for j in range(2, i): if i % j == 0: found = False break if found: print("{} is a prime number".format(i)) def print_prime2(n): for i in range(2, n): for j in range(2, i): if i % j == 0: break else: print("{} is a prime number".format(i))
當循環「天然」終結(循環條件爲假)時 else
從句會被執行一次,而當循環是由 break
語句中斷時,else
子句就不被執行。
與 for
語句類似,while
語句中的 else
子句的語意是同樣的: else
塊在循環正常結束和循環條件不成立時被執行。
Python中經常使用的異常處理語法是try
、except
、else
、finally
,它們能夠有多種組合。語法形式以下:
# Run this main action first try: <statements> # 當 try 中發生 name1 的異常時,進行處理 except <name1>: <statements> # 當 try 中發生 name2 或 name3 中的某一個異常時 except (name2, name3): <statements> # 當 try 中發生 name4 的異常時處理,並獲取對應實例 except <name4> as <data>: <statements> # 其餘異常時,進行處理 except: <statements> # 沒有異常時,執行 else: <statements> # 不管有沒有異常,都執行 finally: <statements>
異常處理,一般須要遵循如下幾點基本原則:
try
中放入過多的代碼。在 try 中放入過多的代碼帶來的問題是若是程序中拋出異常,將會較難定位,給 debug 和修復帶來不便,所以應儘可能只在可能拋出異常的語句塊前面放入 try 語句。except
語句處理全部異常,最好能定位具體的異常。一樣也不推薦使用 except Exception
或者 except StandardError
來捕獲異常。若是必須使用,最好可以使用 raise
語句將異常拋出向上層傳遞。except
語句中拋出,而父類異常在後面的 except
語句拋出。這樣作的緣由是當 try
塊中有異常發生的時候,解釋器根據 except
聲明的順序進行匹配,在第一個匹配的地方便當即處理該異常。不管 try
語句中是否有異常拋出,finally
語句總會被執行。因爲這個特性,finally
語句常常被用來作一些清理工做。
但使用 finally
時,也要特別當心一些陷阱。
try
塊中發生異常的時候,若是在 except
語句中找不到對應的異常處理,異常將會被臨時保存起來,當 finally
執行完畢的時候,臨時保存的異常將會再次被拋出,但若是 finally
語句中產生了新的異常或者執行了 return
或者 break
語句,那麼臨時保存的異常將會被丟失,從而致使異常屏蔽。finally
中使用 return
語句進行返回,這種處理方式不只會帶來誤解並且可能會引發很是嚴重的錯誤。Python 中如下數據會看成空來處理:
None
False
0
、0L
、0.0
、0j
''
、()
、[]
{}
__nonzero__()
和 __len__()
方法,而且該方法返回整數 0
或 False
的時候。if list1 # value is not empty Do something else: # value is empty Do some other thing
__nonzero__()
來判斷變量 list1
是否爲空並返回其結果。注:
__nonzero__()
方法 —— 該內部方法用於對自身對象進行空值測試,返回 0/1 或 True/False。
__len__()
方法調用的結果來進行判斷。__len__()
返回值爲 0 則表示爲空。若是一個類中既沒有定義 __len__()
方法也沒有定義 __nonzero__()
方法,該類的實例用 if 判斷的結果都爲 True。.format
方式而不是 %
推薦儘可能使用 format
方式而不是 %
操做符來格式化字符串,理由:
format
方式在使用上較 %
操做符更爲靈活。使用 format
方式時,參數的順序與格式化的順序沒必要徹底相同
format
方式能夠方便的做爲參數傳遞
weather = [("Monday", "rain"), ("Tuesday", "sunny"), ("Wednesday", "sunny"), ("Thursday", "rain"), ("Friday", "cloudy")] formatter = "Weather of '{0[0]}' is '{0[1]}'".format for item in map(formatter, weather): print(item)
%
最終會被 .format 方式所代替。根據 Python 的官方文檔,之因此仍然保留 %
操做符是爲了保持向後兼容
%
方法在某些特殊狀況下使用時須要特別當心,對於 %
直接格式化字符的這種形式,若是字符自己爲元組,則須要使用在 %
使用 (itemname,)
這種形式才能避免錯誤,注意逗號。
Python 中一切皆對象,對象根據其值可否修改分爲可變對象和不可變對象。
不可變對象
可變對象
在將可變對象做爲函數默認參數的時候要特別緊惕,對可變對象的更改會直接影響原對象。
最好的方法是傳入 None
做爲默認參數,在建立對象的時候動態生成可變對象。
對於一個可變對象,切片操做至關於淺拷貝。
對於不可變對象,當咱們對其進行相關操做的時候,Python 實際上仍然保持原來的值並且從新建立一個新的對象,因此字符串對象不容許以索引的方式進行賦值,當有兩個對象同時指向一個字符串對象的時候,對其中一個對象的操做並不會影響另外一個對象。
對於Python中函數的傳參方法,既不是傳值,也不是傳引用。
正確的叫法應該是傳對象(call by object)或者說傳對象的引用(call-by-object-reference)。
函數參數在傳遞的過程當中將整個對象傳入,
慎用可變長度參數*args, **kwargs
,緣由以下:
*args
和 **kwargs
來簡化函數的定義,但一般這個函數能夠有更好的實現方式,應該被重構。例如能夠直接傳入元組和字典。可變長參數適合在下列狀況下使用:
str()
和 repr()
的區別函數 str()
和 repr()
均可以將 Python 中的對象轉換爲字符串,二者的使用以及輸出都很是類似。有如下幾點區別:
二者的目標不一樣:
str()
主要面向用戶,其目的是可讀性,返回形式爲用戶友好性和可讀性都較強的字符串類型repr()
面向開發人員,其目的是準確性,其返回值表示 Python 解釋器內部的含義,經常使用做 debug在解釋器中直接輸入時默認調用 repr()
函數,而 print
則調用 str()
函數
repr()
的返回值通常能夠用 eval()
函數來還原對象。一般有以下等式:obj == eval(repr(obj))
通常,類中都應該定義 __repr__()
方法,而 __str__()
方法則爲可選,當可讀性比準確性更爲重要的時候應該考慮定義 __str__()
方法。若是類中沒有定義 __str__()
方法,則默認會使用 __repr__()
方法的結果來返回對象的字符串表示形式。用戶實現 __repr__()
方法的時,最好保證其返回值能夠用 eval()
方法使對象從新還原。
靜態方法:
class C(object): @staticmethod def f(arg1, arg2, ...):
類方法:
class C(object): @classmethod def f(cls, arg1, arg2, ...):
均可以經過類名.方法名
或者實例.方法名
的形式來訪問。
其中,靜態方法沒有常規方法的特殊行爲,如綁定、非綁定、隱式參數等規則,而類方法的調用使用類自己做爲其隱含參數,但調用自己並不須要顯示提供該參數。
類方法
靜態方法
文章首發於公衆號【Python與算法之路】