第二章 編程慣用法

建議 8:利用assert語句來發(fā)現(xiàn)問題
# 斷言用法
assert expression  
# 等價于以下語句
if not expression:
    raise AssertionError

使用斷言注意以下幾點

1 不要濫用,這是基本原則。若由于斷言已發(fā)了異常,通常代表程序中存在bug。因此斷言應(yīng)該使用在正常邏輯不可能到達的地方活正常情況下總是為真的場合。

2 如果Python本身的異常能夠處理就不要再使用斷言。如對于類似數(shù)組越界、類型匹配、除數(shù)為0之類的錯誤,不建議使用斷言來處理。下面的例子中使用斷言就顯得多余,因為如果傳入的參數(shù)一個為串串,另一個為數(shù)字或者列表,本身就會拋出TypeError。

def stradd(x, y):
    assert isinstance(x, basestring)
    assert isinstance(y, basestring)
    return x+y

3 不要使用斷言來檢查用戶的輸入。如對于一個數(shù)字類型,如果根據(jù)用戶的設(shè)計,該值的范圍是2~10,較好的做法是使用條件判斷,并在不符合條件的時候輸出錯誤提示信息。

4 在函數(shù)調(diào)用后,當需要確認返回值是否合理時可以使用斷言

5 當條件是業(yè)務(wù)邏輯進行下去的先決條件時,可以使用斷言。如list1和其副本list2,業(yè)務(wù)繼續(xù)下去的條件是這兩個list必須是一樣的,但由于某些不可控因素,如使用了淺拷貝而且list1中含有尅安對象,就可以使用斷言來判斷這兩者的關(guān)系,如果相等,則繼續(xù)運行后面的程序意義不大。

建議9:數(shù)據(jù)交換不推薦使用中間變量
# Python推薦使用, 性能更好
x ,y = y, x
# 大家熟悉方式
temp = x
x = y
y = temp
建議10:充分利用Lazy evaluation的特性

1 避免不必要的計算,以便帶來性能上的提升。比如以下示例:

# 當x為False的情況,y將不再計算
if x and y:
    pass

2 節(jié)省空間,使得無限循環(huán)的數(shù)據(jù)結(jié)構(gòu)成為可能。如斐波那契數(shù)列的實現(xiàn)

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

from itertools import islice
print(list(islice(fib(), 5)))
建議11:理解枚舉替代實現(xiàn)的缺陷

在Python3.4以前并沒提供枚舉類型,于是人們充分利用Python的動態(tài)性這個特征,想出來枚舉的各種替代實現(xiàn)方式。

1 使用類屬性

class Seasons:
    Spring = 0
    Summer = 1
    Autumn = 2
    Winter = 3

2 借助函數(shù)

# 定義
def enum(*posarg, **keysarg):
    return type("Enum", (object,), dict(zip(posag, xrange(len(posarg))), **keysarg))

# 使用
Seasons = enum("Spring", "Summer", "Autumn", Winter=1)
print Seasons.Spring  # 0

3 使用collections.namedtuple

Seasons = namedtuple("Seasons", "Spring Summer Autumn Winter")._make(range(4))

Seasons.Spring  # 0

枚舉代替實現(xiàn)方式還有很多,這些方案也有其不合理的地方。

1 枚舉值不唯一
2 帶來一些無意義的操作,如 Seasons.Summer + Seasons.Autumn == Seasons.Winter

還有一種替代方案,第三方模塊 flufl.enum,
請參考: http://Pythonhosted.org/flufl.enum/docs/using.html

建議12: 不推薦使用type來進行類型檢查

不刻意進行類型檢查,而是在出錯的情況下通過拋出異常來進行處理,是較為常見的方式。但實際應(yīng)用中為了提高程序的健壯性,仍然會面臨需要類型檢查的情況。那么用什么方法呢。

1 type(), 所有基本類型對應(yīng)的名稱都可以在types模塊中找到,如types.BooleanType, types.IntType, types.StringType等。為什么不推薦使用呢,因為基于內(nèi)建類型擴展的用戶自定義類型,type函數(shù)并不能準確返回結(jié)果。

if type(a) is types.ListType:
    pass

2 isinstance

isinstance(2, float)  # False
isinstance("a", (str, unicode))  # True
isinstance((2, 3), (str, list, tuple))  # True
建議13:盡量轉(zhuǎn)換為浮點類型后再做除法

在Python2中,借鑒了C預(yù)研的一些規(guī)則,兩個整數(shù)相除,返回值也是整數(shù),運算結(jié)果將直接截斷。Python3中做了一定的修正,已經(jīng)不存在這個問題了。

建議14: 警惕eval()的安全漏洞

如果使用對象不是信任源,應(yīng)該盡量避免使用eval,在使用eval的地方可用安全性更好的ast.literal_evalt替代??梢詤⒖嘉臋n:http://docs.python.org/2/library/ast.html#ast.literal_eval

建議15:使用enumerate()獲取序列迭代的索引和值

使用enumerate(),代碼清晰簡潔,可讀性最好。它具有一定的惰性,每次盡在需要的時候財貨產(chǎn)生一個(index, item)對。

li = ["a", "b", "c", "d", "e"]
for i, e in enumerate(li):
    print "index: ", i, "element: ", e

enumerate()函數(shù)的內(nèi)如實現(xiàn)非常簡單,enumerate(sequence, start=0)實際相當于如下代碼

def enumerate(sequence, start=0):
    n = start
for elem in sequence:
    yield n, elem
    n += 1

對于字典的迭代循環(huán),enumerate()并不適合,輸出結(jié)果與期望大相徑庭

person_info = {"name": "Jon", "age": "20"}
for k, v in enumerate(person_info):
   print k, v
# 輸出為(Mac, Python2.7.15)
0 name
1 age

要獲取字典迭代過程中的key、value,應(yīng)該使用如下items()方法:

for k, v in person_info.items():
    print k, v
建議16:分清 == 與 is 的適用場景

1 is 表示對象標識符
2 == 表示值是否相等

# 當a、b的值同為短字符串時,a is b為True,python的字符串主流機制,他們指向同一個對象
a = "I am using long string for testing"
b = "I am using long string for testing"
a is b  # False
a == b  # True
建議17:考慮兼容性,盡可能使用Unicode

對于A、B兩種編碼系統(tǒng),相互轉(zhuǎn)換示意圖如下

編碼轉(zhuǎn)換示意圖
建議18:構(gòu)建合理的包層次來管理module

本質(zhì)上每一個Python文件都是一個模塊,使用模塊可以增強代碼的可維護性和可重用性。
什么是包呢?簡單的說包即是目錄,它除了包含常規(guī)的Python文件以外,還包含一個__init__.py

1 合理組織代碼,便于維護和使用
2 能夠有效地避免名稱空間沖突
3 以下一個可供參考的Python項目結(jié)構(gòu)

ProjectName/
   | --- README
   | --- LICENSE
   | --- setup.py
   | --- sample/
   |      | --- __init__.py
   |      | --- core.py
   |      | --- helpers.py
   | --- docs/
   |      | --- config.py
   |      | --- index.rst
   | --- bin/
   | --- package/
   |      | --- __init__.py
   |      | --- subpackage/
   |      | --- ......
   | --- tests/
   |      | --- test_basic.py
   |      | --- test_advanced.py
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容