摘要:本文僅是一個編碼風格的參考,并不是一個規定,規定必須要這么去做。變量類屬性等命令盡量不要使用縮寫形式,除了計數器和迭代器,盡量不要使用單字符名稱。
代碼除了用來運行外,更多的是用來讀。為了是代碼的可讀性更強,很多編程語言都有自己的編碼規范。規范的制定是為了保持代碼的一致性,以使代碼更美觀和易讀。代碼應該怎么樣排版和編寫并不是絕對的,所以一些地方會有爭議。有時風格指南并不適用,最重要的知道何時不一致。當你無法判斷該怎么做時,應該所參考下其他的例子。
本文僅是一個 Python 編碼風格的參考,并不是一個規定,規定必須要這么去做。本文的目的應該是起一個指導作用,指導開發者去寫更易讀的代碼。
一、代碼編排主要是縮進與空行的排版:
1、使用 4 個空格進行縮進(編輯器都可以完成此功能),不推薦使用制表符,更不能混合使用制表符和空格。
2、每行不超過 80 個字符,換行可以使用反斜杠,最好使用括號(Python 會將圓括號, 中括號和花括號中的行隱式的連接起來)。
3、類和頂層函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方盡量不要再空行。
二、文檔編排主要是整個源碼文件的布局:
1、模塊內容的順序:模塊說明,模塊文檔字符串,導入語句,全局變量或者常量,其他定義。
2、模塊導入部分順序:標準庫,第三方模塊,自定義模塊;各部分之間空一行。
3、不要在一個 import 語句中一次導入多個模塊,比如 import os, sys 不推薦。
4、導入模塊時應該使用合適的方式來避免命名沖突,例如在適當的時候才使用 from xx import xx,盡量避免使用 from xx imoprt *。
5、在自已編寫的模塊中,如果需要使用 from xx import * 時,應該在導入語句后或者模塊尾使用 __all__ 機制來限制導入規則。
三、語句編排1、通常每個語句應該獨占一行。
2、不要在行尾加分號, 也不要用分號將多條語句放在同一行。
3、if/for/while 語句中,即使執行語句只有一句,也應盡量另起一行。
4、不要在返回語句(return)或條件語句(if/for/while)中使用括號,除非是用于實現行連接。
5、對于 if 語句, 在沒有 else 且語句比較短時,可以在一行完成(但不推薦),比如:if foo: bar(foo).
6、對于簡單的類定義,也可以在一行完成(但不推薦),比如定義一個異常:class UnfoundError(Exception): pass.
7、函數和方法的括號中使用垂直隱式縮進或使用懸掛縮進。
# 一行寫不下時,有括號來連接多行,后續行應該使用懸掛縮進 if (this_is_one_thing and that_is_another_thing): do_something() # 函數調用參數較多時,對準左括號 f = foo(a, b, c, d) # 不對準左括號,但加多一層縮進,以和后面內容區別 def long_function_name( a, b, c, d, e): print(a, b, c, d, e) # 列表、元組、字典以及函數調用時可以讓右括號回退,這樣更加美觀 l = [ 1, 2, 3, 4, 5, 6, ] result = some_function( "a", "b", "c", "d", "e", "f", )四、空格使用
總體原則,避免不必要的空格。
1、各種右括號前不要加空格。
2、逗號、冒號、分號前不要加空格,但應該在它們后面加(除了在行尾)。
3、函數的左括號前不要加空格。如 Func(1)。
4、序列的左括號前不要加空格。如 list[2]。
5、操作符左右各加一個空格,不要為了對齊增加空格。
6、函數默認參數使用的賦值符左右省略空格。
良好的風格:
spam(ham[1], {eggs: 2}) if x == 4: print x, y; x, y = y, x f = foo(1, 2, 3) ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] ham[lower:upper], ham[lower:upper:], ham[lower::step] ham[lower+offset : upper+offset] ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)] ham[lower + offset : upper + offset] x = 1 y = 2 long_variable = 3 def foo(a, b, c=0): return moo(m=a, n=b, o=c)
不好的風格:
spam( ham[ 1 ], { eggs: 2 } ) if x == 4 : print x , y ; x , y = y , x f = foo (1, 2, 3) ham[lower + offset:upper + offset] ham[1: 9], ham[1 :9], ham[1:9 :3] ham[lower : : upper] ham[ : upper] x = 1 y = 2 long_variable = 3 def foo(a, b, c = 0): return moo(m = a, n = b, o = c)五、注釋
總體原則,錯誤的注釋不如沒有注釋。所以當一段代碼發生變化時,第一件事就是要修改注釋。注釋盡量使用英文,最好是完整的句子,首字母大寫,句后要有結束符,結束符后跟兩個空格,開始下一句。如果是短語,可以省略結束符。注釋應該在 # 后加一個空格才開始寫注釋內容。
1、塊注釋,在一段代碼前增加的注釋。段落之間用只有 ‘#’ 的行間隔。比如:
# Description : Module config. # # Input : None # # Output : None
2、行注釋,在一句代碼后加注釋。應該盡量在語句后空兩格后再開始注釋。當有連續的行注釋時,為了美觀可以讓 ‘#’ 對齊。 在語句比較長時,應該盡量少使用行注釋。比如:
person = { "name": "huoty", # 姓名 "age": 26, # 年齡 "stature": 169, # 身高 "weight": 60, # 體重 } print person # 輸出信息
3、對類或者函數的說明,盡量不要在其定義的前一行或者后一行用塊注釋的形式來說明,而應該使用文檔字符串(docstring)
4、使用 TODO 注釋來標記待完成的工作,團隊協作中,必要的時候應該寫上你的名字或者聯系方式,比如:
# TODO(sudohuoty@gmail.com): Use a "*" here for string repetition. # TODO(Huoty) Change this to use relations.
5、避免無謂的注釋。你見過哪些奇趣的代碼注釋?
# 你可能會認為你讀得懂以下的代碼。但是你不會懂的,相信我吧。 # 要是你嘗試玩弄這段代碼的話,你將會在無盡的通宵中不斷地咒罵自己為什么會認為自己聰明到可以優化這段代碼。 # so,現在請關閉這個文件去玩點別的吧。 # 程序員1(于2010年6月7日):在這個坑臨時加入一些調料 # 程序員2(于2011年5月22日):臨你個屁啊 # 程序員3(于2012年7月23日):樓上都是狗屎,鑒定完畢 # 程序員4(于2013年8月2日):fuck 樓上,三年了,這坑還在!!! # 程序員5(于2014年8月21日):哈哈哈,這坑居然坑了這么多人,幸好我也不用填了,系統終止運行了,you"re died六、文檔描述
1、盡量為所有的共有模塊、函數、類、方法寫 docstring。
2、前三引號后不應該換行,應該緊接著在后面概括性的說明模塊、函數、類、方法的作用,然后再空一行進行詳細的說明。后三引號應該多帶帶占一行。比如:
"""Convert an API path to a filesystem path If given, root will be prepended to the path. root must be a filesystem path already. """
2、函數和方法的 docstring 層次順序大致為概述、詳細描述、參數、返回值、異常,一般不要求描述實現細節,除非其中涉及非常復雜的算法。大致的層次結構如下所示:
"""函數或方法的概述 詳細的描述信息…… 詳細的描述信息…… 參數說明 -------- 參數1:... 參數2:... 返回值: ... 異常: 異常1:... 異常2:... """
一個參考示例:
"""Start a kernel for a session and return its kernel_id. Parameters ---------- kernel_id : uuid The uuid to associate the new kernel with. If this is not None, this kernel will be persistent whenever it is requested. path : API path The API path (unicode, "/" delimited) for the cwd. Will be transformed to an OS path relative to root_dir. kernel_name : str The name identifying which kernel spec to launch. This is ignored if an existing kernel is returned, but it may be checked in the future. Return a kernel id """
3、類的 docstring 的層次順序大致為概述、詳細描述、屬性說明。如果類有公開屬性值時,應該盡量在 docstring 中進行說明。如下所示:
"""這里是類的概述。 詳細的描述信息…… 詳細的描述信息…… 屬性(Attributes): ----------------- 屬性1: ... 屬性2: ... """七、命名規范
1、模塊命名盡量短小,使用全部小寫的方式,可以使用下劃線。
2、包命名盡量短小,使用全部小寫的方式,不可以使用下劃線。
3、類的命名使用駝峰命令的方式,即單詞首字符大寫,類名應該全部使用名詞。
4、異常命令應該使用加 Error 后綴的方式,比如:HTTPError。
5、全局變量盡量只在模塊內有效,并且應該盡量避免使用全局變量。
6、函數命名使用全部小寫的方式,使用下劃線分割單詞,并采用動賓結構。
7、常量命名使用全部大寫的方式,使用下劃線分割單詞。
8、類的屬性(方法和變量)命名使用全部小寫的方式,使用下劃線分割單詞。
9、變量、類屬性等命令盡量不要使用縮寫形式,除了計數器和迭代器,盡量不要使用單字符名稱。
10、類的方法第一個參數必須是 self,而靜態方法第一個參數必須是 cls。
11、在模塊中要表示私有變量或者函數時,可以在變量或者函數前加一個下劃線 _foo, _show_msg 來進行訪問控制。
12、在 Python 中沒有諸如 public、private、protected 等修飾符,而在類的定義中往往會有類似這樣的需求,那么可以在屬性或者方法前加一個下劃線表示 protected,加兩個下劃線來表示 private。加兩個下劃線的變量或者方法沒法直接訪問。比如:類 Foo 中聲明 __a, 則不能用 Foo.__a 的方式訪問,但可以用 Foo._Foo__a 的方式訪問。`
八、程序入口Python 屬于腳本語言,代碼的運行是通過解釋器對代碼文件進行逐行解釋執行來完成的。它不像其他編程語言那樣有統一的入口程序,比如 Java 有 Main 方法,C/C++ 有 main 方法。Python 的代碼文件除了可以被直接執行外,還可以作為模塊被其他文件導入。所有的頂級代碼在模塊導入時都會被執行,當希望模塊被導入時,應該避免主程序被執行。這樣就需要把主程序放到 if __name__ == "__main__" 代碼塊中,比如:
def main(): ... if __name__ == "__main__": main()
一個包除了能夠被導入外,也可以通過 python -m package 的方式被直接執行,前提是包中需要有 __main__.py,這個文件可以說是包的程序入口,包中有了這個文件就可以用 Python 的 -m 參數來直接運行。
九、編碼建議1、盡可能使用 "is" 和 "is not" 取代 "==",比如 if x is not None 要優于 if x != None,另外用 if x 效率更高。
Note: 等于比較運算符(==) 會調用左操作數的 __eq__ 函數,這個函數可以被其任意定義,而 is 操作只是做 id 比較,并不會被自定義。同時也可以發現 is 函數是要快于等于運算符的,因為不用查找和運行函數。
2、用 "is not" 代替 "not ... is",前者的可讀性更好。
3、使用基于類的異常,每個模塊或包都有自己的異常類,此異常類繼承自 Exception。
4、異常中盡量不要使用裸露的 except,except 后應該跟具體的 exceptions。
5、使用 startswith() 和 endswith() 代替切片進行序列前綴或后綴的檢查。
6、使用 isinstance() 比較對象的類型,而不是 type(),比如:
# Yes: if isinstance(obj, int) # No: if type(obj) is type(1)
7、判斷序列是否為空時,不用使用 len() 函數,序列為空時其 bool 值為 False,比如:
# Yes: if not seq if seq # No: if len(seq) if not len(seq)
8、字符串后面不要有大量拖尾空格。
9、使用 join 合并的字符串,字符串方法 join 可以合并 list、tuple、iterator 中的元素,效率比連接符 + 高。
10、使用 while 1 比 while True 更快。
11、使用 ** 比 pow 快 10 倍以上。
12、使用迭代器和生成器代替列表等數據結構效率更高,使用列表(字典)解析式和生成器表達式比用循環效率更高。
13、避免在循環中用 + 或 += 來連續拼接字符串。因為字符串是不變型,這會毫無必要地建立很多臨時對象,從而成為二次方級別的運算量而不是線性運算時間。
14、多去了解標準庫,標準庫中用很多好用的功能,能夠更優雅的解決問題,如 pkgutil.get_data()、operator.methodcaller() 等等。
參考資料https://www.python.org/dev/pe...
http://www.elias.cn/Python/Py...
https://my.oschina.net/u/1433...
http://nanshu.wang/post/2015-...
https://zhuanlan.zhihu.com/p/...
https://zhuanlan.zhihu.com/p/...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43096.html
摘要:原文介紹這篇文檔給出了語言編碼的風格約定,包括中用實現的部分。譯者注不清楚這里是什么意思,括號中原文為語言版本使用標準年版本。這意味著在許多其他事情中所有聲明必須放在某個塊的頂部并不一定是函數的頂部。 原文http://legacy.python.org/dev/peps/pep-0007/ 介紹 這篇文檔給出了C語言編碼的風格約定,包括Python中用C實現的部分。關于P...
摘要:原文作者原題的代碼庫使用編碼風格。此外,推薦的用于連續行的編碼風格毫無一點品味,絕不允許在代碼庫使用與開局定界符對齊。但是,關于靈活設定行長的部分,我舉雙手雙腳贊同。關于代碼風格,沒有絕對完全一致的標準。 showImg(https://segmentfault.com/img/bVbnv2L?w=6000&h=4000); 原文:https://www.kennethreitz.or...
摘要:有一些定制類的特殊方法,如,其中一些具有動態特性的方法可以用來很方便地處理某些動態狀況。動態化屬性和方法的調用,當調用不存在的屬性時,如果存在方法,就會調用方法來嘗試獲得屬性。這種完全動態的調用可以應對一些動態情況,例如實現。 Python有一些定制類的特殊方法,如__str__()、__iter__()、__getitem__(),其中一些具有動態特性的方法可以用來很方便地處理某些動...
閱讀 765·2019-08-29 16:32
閱讀 836·2019-08-29 12:31
閱讀 3208·2019-08-26 18:26
閱讀 3152·2019-08-26 12:20
閱讀 1728·2019-08-26 12:00
閱讀 3006·2019-08-26 10:58
閱讀 2811·2019-08-23 17:08
閱讀 2309·2019-08-23 16:32