Python 風格規範html
main 分號 行長度 括號 縮進 空行 空格 Shebang
python
Tipapi
即便是一個打算被用做腳本的文件, 也應該是可導入的. 而且簡單的導入不該該致使這個腳本的主功能(main functionality)被執行, 這是一種反作用. 主功能應該放在一個main()函數中.緩存
在Python中, pydoc以及單元測試要求模塊必須是可導入的. 你的代碼應該在執行主程序前老是檢查if __name__ == '__main__'
, 這樣當模塊被導入時主程序就不會被執行.app
def main(): ... if __name__ == '__main__': main()
全部的頂級代碼在模塊導入時都會被執行. 要當心不要去調用函數, 建立對象, 或者執行那些不該該在使用pydoc時執行的操做.socket
Tip函數
不要在行尾加分號, 也不要用分號將兩條命令放在同一行.單元測試
Tip
每行不超過80個字符
例外:
不要使用反斜槓鏈接行.
Python會將 圓括號, 中括號和花括號中的行隱式的鏈接起來 , 你能夠利用這個特色. 若是須要, 你能夠在表達式外圍增長一對額外的圓括號.
Yes: foo_bar(self, width, height, color='black', design=None, x='foo', emphasis=None, highlight=0) if (width == 0 and height == 0 and color == 'red' and emphasis == 'strong'):
若是一個文本字符串在一行放不下, 可使用圓括號來實現隱式行鏈接:
x = ('This will build a very long long ' 'long long long long long long string')
在註釋中,若是必要,將長的URL放在一行上。
Yes: # See details at # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
No: # See details at # http://www.example.com/us/developer/documentation/api/content/\ # v2.0/csv_file_name_extension_full_specification.html
注意上面例子中的元素縮進; 你能夠在本文的 縮進 部分找到解釋.
Tip
寧缺毋濫的使用括號
除非是用於實現行鏈接, 不然不要在返回語句或條件語句中使用括號. 不過在元組兩邊使用括號是能夠的.
Yes: if foo: bar() while x: x = bar() if x and y: bar() if not x: bar() return foo for (x, y) in dict.items(): ...
No: if (x): bar() if not(x): bar() return (foo)
Tip
用4個空格來縮進代碼
絕對不要用tab, 也不要tab和空格混用. 對於行鏈接的狀況, 你應該要麼垂直對齊換行的元素(見 行長度 部分的示例), 或者使用4空格的懸掛式縮進(這時第一行不該該有參數):
Yes: # Aligned with opening delimiter foo = long_function_name(var_one, var_two, var_three, var_four) # Aligned with opening delimiter in a dictionary foo = { long_dictionary_key: value1 + value2, ... } # 4-space hanging indent; nothing on first line foo = long_function_name( var_one, var_two, var_three, var_four) # 4-space hanging indent in a dictionary foo = { long_dictionary_key: long_dictionary_value, ... }
No: # Stuff on first line forbidden foo = long_function_name(var_one, var_two, var_three, var_four) # 2-space hanging indent forbidden foo = long_function_name( var_one, var_two, var_three, var_four) # No hanging indent in a dictionary foo = { long_dictionary_key: long_dictionary_value, ... }
Tip
頂級定義之間空兩行, 方法定義之間空一行
頂級定義之間空兩行, 好比函數或者類定義. 方法定義, 類定義與第一個方法之間, 都應該空一行. 函數或方法中, 某些地方要是你以爲合適, 就空一行.
Tip
按照標準的排版規範來使用標點兩邊的空格
括號內不要有空格.
Yes: spam(ham[1], {eggs: 2}, [])
No: spam( ham[ 1 ], { eggs: 2 }, [ ] )
不要在逗號, 分號, 冒號前面加空格, 但應該在它們後面加(除了在行尾).
Yes: if x == 4: print x, y x, y = y, x
No: if x == 4 : print x , y x , y = y , x
參數列表, 索引或切片的左括號前不該加空格.
Yes: spam(1)
no: spam (1)
Yes: dict['key'] = list[index]
No: dict ['key'] = list [index]
在二元操做符兩邊都加上一個空格, 好比賦值(=), 比較(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布爾(and, or, not). 至於算術操做符兩邊的空格該如何使用, 須要你本身好好判斷. 不過兩側務必要保持一致.
Yes: x == 1
No: x<1
當’=’用於指示關鍵字參數或默認參數值時, 不要在其兩側使用空格.
Yes: def complex(real, imag=0.0): return magic(r=real, i=imag)
No: def complex(real, imag = 0.0): return magic(r = real, i = imag)
不要用空格來垂直對齊多行間的標記, 由於這會成爲維護的負擔(適用於:, #, =等):
Yes: foo = 1000 # comment long_name = 2 # comment that should not be aligned dictionary = { "foo": 1, "long_name": 2, }
No: foo = 1000 # comment long_name = 2 # comment that should not be aligned dictionary = { "foo" : 1, "long_name": 2, }
Tip
大部分.py文件沒必要以#!做爲文件的開始. 根據 PEP-394 , 程序的main文件應該以 #!/usr/bin/python2或者 #!/usr/bin/python3開始.
(譯者注: 在計算機科學中, Shebang (也稱爲Hashbang)是一個由井號和歎號構成的字符串行(#!), 其出如今文本文件的第一行的前兩個字符. 在文件中存在Shebang的狀況下, 類Unix操做系統的程序載入器會分析Shebang後的內容, 將這些內容做爲解釋器指令, 並調用該指令, 並將載有Shebang的文件路徑做爲該解釋器的參數. 例如, 以指令#!/bin/sh開頭的文件在執行時會實際調用/bin/sh程序.)
#!先用於幫助內核找到Python解釋器, 可是在導入模塊時, 將會被忽略. 所以只有被直接執行的文件中才有必要加入#!.
Tip
若是一個類不繼承自其它類, 就顯式的從object繼承. 嵌套類也同樣.
Yes: class SampleClass(object): pass class OuterClass(object): class InnerClass(object): pass class ChildClass(ParentClass): """Explicitly inherits from another class already."""
No: class SampleClass: pass class OuterClass: class InnerClass: pass
繼承自 object
是爲了使屬性(properties)正常工做, 而且這樣能夠保護你的代碼, 使其不受Python 3000的一個特殊的潛在不兼容性影響. 這樣作也定義了一些特殊的方法, 這些方法實現了對象的默認語義, 包括__new__, __init__, __delattr__, __getattribute__, __setattr__, __hash__, __repr__, and __str__
.
Tip
即便參數都是字符串, 使用%操做符或者格式化方法格式化字符串. 不過也不能一律而論, 你須要在+和%之間好好斷定.
Yes: x = a + b x = '%s, %s!' % (imperative, expletive) x = '{}, {}!'.format(imperative, expletive) x = 'name: %s; score: %d' % (name, n) x = 'name: {}; score: {}'.format(name, n)
No: x = '%s%s' % (a, b) # use + in this case x = '{}{}'.format(a, b) # use + in this case x = imperative + ', ' + expletive + '!' x = 'name: ' + name + '; score: ' + str(n)
避免在循環中用+和+=操做符來累加字符串. 因爲字符串是不可變的, 這樣作會建立沒必要要的臨時對象, 而且致使二次方而不是線性的運行時間. 做爲替代方案, 你能夠將每一個子串加入列表, 而後在循環結束後用 .join
鏈接列表. (也能夠將每一個子串寫入一個 cStringIO.StringIO
緩存中.)
Yes: items = ['<table>'] for last_name, first_name in employee_list: items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name)) items.append('</table>') employee_table = ''.join(items)
No: employee_table = '<table>' for last_name, first_name in employee_list: employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name) employee_table += '</table>'
在同一個文件中, 保持使用字符串引號的一致性. 使用單引號’或者雙引號」之一用以引用字符串, 並在同一文件中沿用. 在字符串內可使用另一種引號, 以免在字符串中使用. GPyLint已經加入了這一檢查.
(譯者注:GPyLint疑爲筆誤, 應爲PyLint.)
Yes: Python('Why are you hiding your eyes?') Gollum("I'm scared of lint errors.") Narrator('"Good!" thought a happy Python reviewer.')
No: Python("Why are you hiding your eyes?") Gollum('The lint. It burns. It burns us.') Gollum("Always the great lint. Watching. Watching.")
爲多行字符串使用三重雙引號」「」而非三重單引號’‘’. 當且僅當項目中使用單引號’來引用字符串時, 纔可能會使用三重’‘’爲非文檔字符串的多行字符串來標識引用. 文檔字符串必須使用三重雙引號」「」. 不過要注意, 一般用隱式行鏈接更清晰, 由於多行字符串與程序其餘部分的縮進方式不一致.
Yes: print ("This is much nicer.\n" "Do it this way.\n")
No: print """This is pretty ugly. Don't do this. """
Tip
在文件和sockets結束時, 顯式的關閉它.
除文件外, sockets或其餘相似文件的對象在沒有必要的狀況下打開, 會有許多反作用, 例如:
並且, 幻想當文件對象析構時, 文件和sockets會自動關閉, 試圖將文件對象的生命週期和文件的狀態綁定在一塊兒的想法, 都是不現實的. 由於有以下緣由:
推薦使用 「with」語句 以管理文件:
with open("hello.txt") as hello_file: for line in hello_file: print line
對於不支持使用」with」語句的相似文件的對象,使用 contextlib.closing():
import contextlib with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page: for line in front_page: print line
Legacy AppEngine 中Python 2.5的代碼如使用」with」語句, 須要添加 「from __future__ import with_statement」.
Tip
爲臨時代碼使用TODO註釋, 它是一種短時間解決方案. 不算完美, 但夠好了.
TODO註釋應該在全部開頭處包含」TODO」字符串, 緊跟着是用括號括起來的你的名字, email地址或其它標識符. 而後是一個可選的冒號. 接着必須有一行註釋, 解釋要作什麼. 主要目的是爲了有一個統一的TODO格式, 這樣添加註釋的人就能夠搜索到(並能夠按需提供更多細節). 寫了TODO註釋並不保證寫的人會親自解決問題. 當你寫了一個TODO, 請註上你的名字.
# TODO(kl@gmail.com): Use a "*" here for string repetition.
# TODO(Zeke) Change this to use relations.
若是你的TODO是」未來作某事」的形式, 那麼請確保你包含了一個指定的日期(「2009年11月解決」)或者一個特定的事件(「等到全部的客戶均可以處理XML請求就移除這些代碼」).
Tip
每一個導入應該獨佔一行
Yes: import os import sys
No: import os, sys
導入總應該放在文件頂部, 位於模塊註釋和文檔字符串以後, 模塊全局變量和常量以前. 導入應該按照從最通用到最不通用的順序分組:
每種分組中, 應該根據每一個模塊的完整包路徑按字典序排序, 忽略大小寫.
import foo from foo import bar from foo.bar import baz from foo.bar import Quux from Foob import ar
Tip
一般每一個語句應該獨佔一行
不過, 若是測試結果與測試語句在一行放得下, 你也能夠將它們放在同一行. 若是是if語句, 只有在沒有else時才能這樣作. 特別地, 毫不要對 try/except
這樣作, 由於try和except不能放在同一行.
Yes: if foo: bar(foo)
No: if foo: bar(foo) else: baz(foo) try: bar(foo) except ValueError: baz(foo) try: bar(foo) except ValueError: baz(foo)
Tip
在Python中, 對於瑣碎又不過重要的訪問函數, 你應該直接使用公有變量來取代它們, 這樣能夠避免額外的函數調用開銷. 當添加更多功能時, 你能夠用屬性(property)來保持語法的一致性.
(譯者注: 重視封裝的面向對象程序員看到這個可能會很反感, 由於他們一直被教育: 全部成員變量都必須是私有的! 其實, 那真的是有點麻煩啊. 試着去接受Pythonic哲學吧)
另外一方面, 若是訪問更復雜, 或者變量的訪問開銷很顯著, 那麼你應該使用像 get_foo()
和 set_foo()
這樣的函數調用. 若是以前的代碼行爲容許經過屬性(property)訪問 , 那麼就不要將新的訪問函數與屬性綁定. 這樣, 任何試圖經過老方法訪問變量的代碼就無法運行, 使用者也就會意識到複雜性發生了變化.
Tip
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.
應該避免的名稱
- 單字符名稱, 除了計數器和迭代器.
- 包/模塊名中的連字符(-)
- 雙下劃線開頭並結尾的名稱(Python保留, 例如__init__)
命名約定
- 所謂」內部(Internal)」表示僅模塊內可用, 或者, 在類內是保護或私有的.
- 用單下劃線(_)開頭表示模塊變量或函數是protected的(使用import * from時不會包含).
- 用雙下劃線(__)開頭的實例變量或方法表示類內私有.
- 將相關的類和頂級函數放在同一個模塊裏. 不像Java, 不必限制一個類一個模塊.
- 對類名使用大寫字母開頭的單詞(如CapWords, 即Pascal風格), 可是模塊名應該用小寫加下劃線的方式(如lower_with_under.py). 儘管已經有不少現存的模塊使用相似於CapWords.py這樣的命名, 但如今已經不鼓勵這樣作, 由於若是模塊名碰巧和類名一致, 這會讓人困擾.
Python之父Guido推薦的規範
Type | Public | Internal |
---|---|---|
Modules | lower_with_under | _lower_with_under |
Packages | lower_with_under | |
Classes | CapWords | _CapWords |
Exceptions | CapWords | |
Functions | lower_with_under() | _lower_with_under() |
Global/Class Constants | CAPS_WITH_UNDER | _CAPS_WITH_UNDER |
Global/Class Variables | lower_with_under | _lower_with_under |
Instance Variables | lower_with_under | _lower_with_under (protected) or __lower_with_under (private) |
Method Names | lower_with_under() | _lower_with_under() (protected) or __lower_with_under() (private) |
Function/Method Parameters | lower_with_under | |
Local Variables | lower_with_under |
註釋
Tip
確保對模塊, 函數, 方法和行內註釋使用正確的風格
文檔字符串
模塊
函數和方法
類
塊註釋和行註釋