Python編程規(guī)范規(guī)范修煉-Google編程規(guī)范解讀

規(guī)范修煉-Google編程規(guī)范解讀

Guido van Rossum(吉多·范羅蘇姆稍途,Python 創(chuàng)始人 )說過,代碼的閱讀頻率遠高于編寫代碼的頻率突勇。畢竟甲馋,即使是在編寫代碼的時候定躏,你也需要對代碼進行反復閱讀和調試芹敌,來確認代碼能夠按照期望運行氏捞。

接下來我們今天就為大家分享《Python編程規(guī)范:讓你的代碼腳下生風》第三彈《Google開源項目風格指南》

Python是Google主要的腳本語言。這本風格指南主要包含的是針對python的編程規(guī)范液茎。

Google開源項目風格指南-Python風格指南包含以下兩個主要內容

  1. Python風格規(guī)范

  2. Python語言規(guī)范

文檔地址: Google開源項目風格指南

一哼凯、Python風格規(guī)范

在Google的Python風格規(guī)范中主要涉及了像如何使用縮進、空格和代碼行的長度班缎、注釋她渴、文檔以及老生常談的命名規(guī)范沉唠、分號的使用满葛、導入格式等嘀韧,這些基本上在前面的分享中都提及過篇亭,這里就不在過多解釋。

但是在Google風格規(guī)范中提及了Main的使用锄贷,我認為這個還是比較重要的內容译蒂。

首先我們知道Python語音的一個特點就是模塊與包,我們可以在程序中導入第三方模塊或者包谊却,當然也可以在項目中自定義模塊與包柔昼,這樣的做法會讓我們把一些功能的實現(xiàn)進行封裝,剩下的只需要關注我們當前的業(yè)務代碼即可因惭。

因此我們在模塊文件或者自定義模塊時中總是能夠看到或使用下面這樣的語句岳锁。

def main():
     print('run')

if __name__ == '__main__':
    main()

‘’‘
__name__ 是當前模塊名,當模塊被直接運行時模塊名為 ‘__main__’
一般我們會在模塊測試時蹦魔,把相關的調用或者執(zhí)行放在`if __name__ == '__main__'`當中激率。
這樣可以保證我們的測試代碼不會在模塊被導入時執(zhí)行低缩,而只是在模塊被作為主程序時執(zhí)行。
’‘’

這是一種很好的特性银觅,而我們在進行模塊開發(fā)時也變的更加方便洒忧,那么接下來我們看一下在Google編碼規(guī)范中時如何對Main的使用進行規(guī)范化的。

Main

即使是一個打算被用作腳本的文件, 也應該是可導入的. 并且簡單的導入不應該導致這個腳本的主功能(main functionality)被執(zhí)行, 這是一種副作用. 主功能應該放在一個main()函數(shù)中.

在Python中, pydoc以及單元測試要求模塊必須是可導入的.

你的代碼應該在執(zhí)行主程序前總是檢查 if __name__ == '__main__' ,

這樣當模塊被導入時主程序就不會被執(zhí)行.

def main():
     print('run')

if __name__ == '__main__':
    main()

所有的頂級代碼在模塊導入時都會被執(zhí)行.

要小心不要去調用函數(shù), 創(chuàng)建對象, 或者執(zhí)行那些不應該在使用pydoc時執(zhí)行的操作.

二减余、 Python語言規(guī)范

接下來我們一起看下《Google開源項目風格指南》中對Python語言的一些規(guī)范吧

1.Lint

對你的代碼運行pylint,pylint是一個在Python源代碼中查找bug的工具.

可以捕獲容易忽視的錯誤, 例如輸入錯誤, 使用未賦值的變量等.

2.導入

僅對包和模塊使用導入.并且必要時使用as

3.包

使用模塊的全路徑名來導入每個模塊

4.異常

允許使用異常, 但必須小心抒抬。

總結幾點如下:

  • 永遠不要使用 except: 語句來捕獲所有異常, 也不要捕獲 Exception 或者 StandardError , 除非你打算重新觸發(fā)該異常, 或者你已經在當前線程的最外層(記得還是要打印一條錯誤消息). 在異常這方面, Python非常寬容, except: 真的會捕獲包括Python語法錯誤在內的任何錯誤. 使用 except: 很容易隱藏真正的bug.
  • 盡量減少try/except塊中的代碼量. try塊的體積越大, 期望之外的異常就越容易被觸發(fā). 這種情況下, try/except塊將隱藏真正的錯誤.
  • 使用finally子句來執(zhí)行那些無論try塊中有沒有異常都應該被執(zhí)行的代碼. 這對于清理資源常常很有用, 例如關閉文件.

5.全局變量

避免全局變量,導入時可能改變模塊行為, 因為導入模塊時會對模塊級變量賦值.

避免使用全局變量, 用類變量來代替. 但也有一些例外:

  1. 腳本的默認選項.
  2. 模塊級常量. 例如: PI = 3.14159. 常量應該全大寫, 用下劃線連接.
  3. 有時候用全局變量來緩存值或者作為函數(shù)返回值很有用.
  4. 如果需要, 全局變量應該僅在模塊內部可用, 并通過模塊級的公共函數(shù)來訪問.

6.嵌套/局部/內部類或函數(shù)

鼓勵使用嵌套/本地/內部類或函數(shù)

定義:

  • 類可以定義在方法, 函數(shù)或者類中.
  • 函數(shù)可以定義在方法或函數(shù)中.
  • 封閉區(qū)間中定義的變量對嵌套函數(shù)是只讀的.

優(yōu)點: 允許定義僅用于有效范圍的工具類和函數(shù).

缺點: 嵌套類或局部類的實例不能序列化(pickled).

結論: 推薦使用.

7.列表推導(List Comprehensions)

可以在簡單情況下使用,復雜的列表推導或者生成器表達式可能難以閱讀.

先看結論

簡單的列表推導可以比其它的列表創(chuàng)建方法更加清晰簡單.

但是復雜的列表推導或者生成器表達式可能難以閱讀.

因此

列表推導適用于簡單情況. 每個部分應該單獨置于一行: 映射表達式, for語句, 過濾器表達式.

禁止多重for語句或過濾器表達式. 復雜情況下還是使用循環(huán).

下面是一些代碼示例,可以感受一下

# 適用于簡單情況. 
# 每個部分應該單獨置于一行: 映射表達式, for語句, 過濾器表達式. 
# 禁止多重for語句或過濾器表達式. 復雜情況下還是使用循環(huán).

# Yes:
result = []
for x in range(10):
    for y in range(5):
        if x * y > 10:
            result.append((x, y))

for x in xrange(5):
    for y in xrange(5):
        if x != y:
            for z in xrange(5):
                if y != z:
                    yield (x, y, z)


# No:
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

return ((x, y, z)
        for x in xrange(5)
        for y in xrange(5)
        if x != y
        for z in xrange(5)
        if y != z)

8.默認迭代器和操作符

如果類型支持, 就使用默認迭代器和操作符. 比如列表, 字典及文件等.

優(yōu)點:

  • 默認操作符和迭代器簡單高效, 它們直接表達了操作, 沒有額外的方法調用.

  • 使用默認操作符的函數(shù)是通用的. 它可以用于支持該操作的任何類型.

缺點:

  • 你沒法通過閱讀方法名來區(qū)分對象的類型(例如, has_key()意味著字典). 不過這也是優(yōu)點.
# 內建類型也定義了迭代器方法. 優(yōu)先考慮這些方法, 而不是那些返回列表的方法. 
# 當然族铆,這樣遍歷容器時献丑,你將不能修改容器.

# Yes:  
for key in adict: ...
if key not in adict: ...
if obj in alist: ...
for line in afile: ...
for k, v in dict.iteritems(): ...

# No: 
for key in adict.keys(): ...
if not adict.has_key(key): ...
for line in afile.readlines(): ...

9.生成器

按需使用生成器.

生成器的定義:

所謂生成器函數(shù), 就是每當它執(zhí)行一次生成(yield)語句, 它就返回一個迭代器, 這個迭代器生成一個值.

生成值后, 生成器函數(shù)的運行狀態(tài)將被掛起, 直到下一次生成.

優(yōu)點:簡化代碼, 因為每次調用時, 局部變量和控制流的狀態(tài)都會被保存. 比起一次創(chuàng)建一系列值的函數(shù), 生成器使用的內存更少.

鼓勵使用. 注意在生成器函數(shù)的文檔字符串中使用”Yields:”而不是”Returns:”.

10.Lambda函數(shù)

適用于單行函數(shù).

優(yōu)點:方便莽红。

缺點:比本地函數(shù)更難閱讀和調試. 沒有函數(shù)名意味著堆棧跟蹤更難理解. 由于lambda函數(shù)通常只包含一個表達式, 因此其表達能力有限.

結論:適用于單行函數(shù). 如果代碼超過60-80個字符, 最好還是定義成常規(guī)(嵌套)函數(shù).

11.條件表達式

條件表達式是對于if語句的一種更為簡短的句法規(guī)則. 例如: x = 1 if cond else 2 .

優(yōu)點:比if語句更加簡短和方便.

缺點:比if語句難于閱讀. 如果表達式很長网棍, 難于定位條件.

結論:適用于單行函數(shù). 在其他情況下惑畴,推薦使用完整的if語句.

12.默認參數(shù)值

適用于大部分情況杠袱。

# 不要在函數(shù)或方法定義中使用可變對象作為默認值.
Yes: def foo(a, b=None):
         if b is None:
             b = []
No:  def foo(a, b=[]):
         ...
No:  def foo(a, b=time.time()):  # The time the module was loaded???
         ...
No:  def foo(a, b=FLAGS.my_thing):  # sys.argv has not yet been parsed...
         ...

結論:鼓勵使用菩彬,但需要注意:不要在函數(shù)或方法定義中使用可變對象作為默認值.

13.True/False的求值

盡可能使用隱式false,

Python在布爾上下文中會將某些值求值為false. 按簡單的直覺來講, 就是所有的”空”值都被認為是false.

因此0耙旦, None, [], {}, “” 都被認為是false.

優(yōu)點: 使用Python布爾值的條件語句更易讀也更不易犯錯. 大部分情況下, 也更快.

結論: 盡可能使用隱式的false, 例如: 使用 if foo:而不是 if foo != []:

不過還是有一些注意事項需要你銘記在心:

# 1. 永遠不要用==或者!=來比較單件, 比如None. 使用is或者is not.

# 2. 注意: 當你寫下 `if x:` 時, 你其實表示的是 `if x is not None` . 

# 3. 永遠不要用==將一個布爾量與false相比較. 使用 `if not x:` 代替. 
#    如果你需要區(qū)分false和None, 你應該用像 `if not x and x is not None:` 這樣的語句.

# 4. 對于序列(字符串, 列表, 元組), 要注意空序列是false. 
#    因此 `if not seq:` 或者 `if seq:` 比 `if len(seq):` 或 `if not len(seq):` 要更好.

# 5. 處理整數(shù)時, 使用隱式false可能會得不償失(即不小心將None當做0來處理). 
#    你可以將一個已知是整型(且不是len()的返回結果)的值與0比較.

# Yes: 
     if not users:
         print 'no users'

     if foo == 0:
         self.handle_zero()

     if i % 10 == 0:
         self.handle_multiple_of_ten()
         
#No:  
         if len(users) == 0:
         print 'no users'

     if foo is not None and not foo:
         self.handle_zero()

     if not i % 10:
         self.handle_multiple_of_ten()
        
# 注意‘0’(字符串)會被當做true.

14.函數(shù)與方法裝飾器

如果好處很顯然, 就明智而謹慎的使用裝飾器

優(yōu)點:優(yōu)雅的在函數(shù)上指定一些轉換. 該轉換可能減少一些重復代碼, 保持已有函數(shù)不變(enforce invariants), 等.

缺點:

  • 裝飾器可以在函數(shù)的參數(shù)或返回值上執(zhí)行任何操作, 這可能導致讓人驚異的隱藏行為.
  • 而且, 裝飾器在導入時執(zhí)行.
  • 從裝飾器代碼的失敗中恢復更加不可能.

結論: 如果好處很顯然, 就明智而謹慎的使用裝飾器,但注意使用

  • 裝飾器應該遵守和函數(shù)一樣的導入和命名規(guī)則.
  • 裝飾器的python文檔應該清晰的說明該函數(shù)是一個裝飾器.
  • 請為裝飾器編寫單元測試.
  • 避免裝飾器自身對外界的依賴(即不要依賴于文件, socket, 數(shù)據庫連接等), 因為裝飾器運行時這些資源可能不可用(由 pydoc 或其它工具導入).
  • 應該保證一個用有效參數(shù)調用的裝飾器在所有情況下都是成功的.
  • 裝飾器是一種特殊形式的”頂級代碼”.

15.線程

優(yōu)先使用Queue模塊的 Queue 數(shù)據類型作為線程間的數(shù)據通信方式.

Python的Queue模塊中提供了同步的险领、線程安全的隊列類臭笆,包括FIFO(先入先出)隊列Queue,LIFO(后入先出)隊列LifoQueue椒拗,和優(yōu)先級隊列PriorityQueue腋舌。

這些隊列都實現(xiàn)了鎖原語世落,能夠在多線程中直接使用圆凰∈徽樱可以使用隊列來實現(xiàn)線程間的同步回怜。

16.威力過大的特性

避免使用這些威力過大的特性

定義:

Python是一種異常靈活的語言, 它為你提供了很多花哨的特性, 諸如元類(metaclasses), 字節(jié)碼訪問, 任意編譯(on-the-fly compilation), 動態(tài)繼承, 對象父類重定義(object reparenting), 導入黑客(import hacks), 反射, 系統(tǒng)內修改(modification of system internals), 等等.

優(yōu)點:

  • 強大的語言特性, 能讓你的代碼更緊湊.

缺點:

  • 使用這些很”酷”的特性十分誘人, 但不是絕對必要. 使用它們將更加難以閱讀和調試.
  • 開始可能還好, 但當你回顧代碼, 它們可能會比那些稍長一點但是很直接的代碼更加難以理解.

結論:莫裝B

Google-Python編碼規(guī)范 總結

在上面的內容中我們對Python中的Main的使用以及針對Python語言特性的語法規(guī)范進行了解讀,那么希望小伙伴們通過本期《Google-Python編碼規(guī)范》以及上一期《Python編程規(guī)范修煉-PEP8規(guī)范解讀》的文章對Python編程的規(guī)范有了一個很深的認知,如果對本期關于編碼規(guī)范的內容進行一個總結的話

請務必保持代碼的一致性

如果你正在編輯代碼, 花幾分鐘看一下周邊代碼, 然后決定風格. 比如如果它們在所有的算術操作符兩邊都使用空格, 那么你也應該這樣做. 如果它們的注釋都用標記包圍起來, 那么你的注釋也要這樣.總之保持風格的統(tǒng)一才是王道

以上就關于分期的分享冲泥,在后面我們還會為大家分享關于Python代碼安全浮还、精簡語句延刘、調試和性能分析以及代碼分解和單元測試等Python編程規(guī)范的系列內容砰嘁,感興趣的小伙伴歡迎關注我的公眾號后廠程序員斟冕。

如果喜歡或者對你有幫助的小伙伴,歡迎大家關注我的公眾號:后廠程序員缅阳,并分享磕蛇、點贊、在看 三連

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末十办,一起剝皮案震驚了整個濱河市秀撇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌向族,老刑警劉巖呵燕,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異件相,居然都是意外死亡虏等,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門适肠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霍衫,“玉大人,你說我怎么就攤上這事侯养《氐” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵逛揩,是天一觀的道長柠傍。 經常有香客問我,道長辩稽,這世上最難降的妖魔是什么惧笛? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮逞泄,結果婚禮上患整,老公的妹妹穿的比我還像新娘。我一直安慰自己喷众,他們只是感情好各谚,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著到千,像睡著了一般昌渤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上憔四,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天膀息,我揣著相機與錄音般眉,去河邊找鬼。 笑死潜支,一個胖子當著我的面吹牛甸赃,可吹牛的內容都是我干的。 我是一名探鬼主播毁腿,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼辑奈,長吁一口氣:“原來是場噩夢啊……” “哼苛茂!你這毒婦竟也來了已烤?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤妓羊,失蹤者是張志新(化名)和其女友劉穎胯究,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躁绸,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡裕循,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了净刮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剥哑。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖淹父,靈堂內的尸體忽然破棺而出株婴,到底是詐尸還是另有隱情,我是刑警寧澤暑认,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布困介,位于F島的核電站,受9級特大地震影響蘸际,放射性物質發(fā)生泄漏座哩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一粮彤、第九天 我趴在偏房一處隱蔽的房頂上張望根穷。 院中可真熱鬧,春花似錦导坟、人聲如沸缠诅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管引。三九已至,卻和暖如春闯两,著一層夾襖步出監(jiān)牢的瞬間褥伴,已是汗流浹背谅将。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留重慢,地道東北人饥臂。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像似踱,于是被迫代替她去往敵國和親隅熙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361