摘要:本文僅是一個(gè)編碼風(fēng)格的參考,并不是一個(gè)規(guī)定,規(guī)定必須要這么去做。變量類屬性等命令盡量不要使用縮寫形式,除了計(jì)數(shù)器和迭代器,盡量不要使用單字符名稱。
代碼除了用來(lái)運(yùn)行外,更多的是用來(lái)讀。為了是代碼的可讀性更強(qiáng),很多編程語(yǔ)言都有自己的編碼規(guī)范。規(guī)范的制定是為了保持代碼的一致性,以使代碼更美觀和易讀。代碼應(yīng)該怎么樣排版和編寫并不是絕對(duì)的,所以一些地方會(huì)有爭(zhēng)議。有時(shí)風(fēng)格指南并不適用,最重要的知道何時(shí)不一致。當(dāng)你無(wú)法判斷該怎么做時(shí),應(yīng)該所參考下其他的例子。
本文僅是一個(gè) Python 編碼風(fēng)格的參考,并不是一個(gè)規(guī)定,規(guī)定必須要這么去做。本文的目的應(yīng)該是起一個(gè)指導(dǎo)作用,指導(dǎo)開(kāi)發(fā)者去寫更易讀的代碼。
一、代碼編排主要是縮進(jìn)與空行的排版:
1、使用 4 個(gè)空格進(jìn)行縮進(jìn)(編輯器都可以完成此功能),不推薦使用制表符,更不能混合使用制表符和空格。
2、每行不超過(guò) 80 個(gè)字符,換行可以使用反斜杠,最好使用括號(hào)(Python 會(huì)將圓括號(hào), 中括號(hào)和花括號(hào)中的行隱式的連接起來(lái))。
3、類和頂層函數(shù)定義之間空兩行;類中的方法定義之間空一行;函數(shù)內(nèi)邏輯無(wú)關(guān)段落之間空一行;其他地方盡量不要再空行。
二、文檔編排主要是整個(gè)源碼文件的布局:
1、模塊內(nèi)容的順序:模塊說(shuō)明,模塊文檔字符串,導(dǎo)入語(yǔ)句,全局變量或者常量,其他定義。
2、模塊導(dǎo)入部分順序:標(biāo)準(zhǔn)庫(kù),第三方模塊,自定義模塊;各部分之間空一行。
3、不要在一個(gè) import 語(yǔ)句中一次導(dǎo)入多個(gè)模塊,比如 import os, sys 不推薦。
4、導(dǎo)入模塊時(shí)應(yīng)該使用合適的方式來(lái)避免命名沖突,例如在適當(dāng)?shù)臅r(shí)候才使用 from xx import xx,盡量避免使用 from xx imoprt *。
5、在自已編寫的模塊中,如果需要使用 from xx import * 時(shí),應(yīng)該在導(dǎo)入語(yǔ)句后或者模塊尾使用 __all__ 機(jī)制來(lái)限制導(dǎo)入規(guī)則。
三、語(yǔ)句編排1、通常每個(gè)語(yǔ)句應(yīng)該獨(dú)占一行。
2、不要在行尾加分號(hào), 也不要用分號(hào)將多條語(yǔ)句放在同一行。
3、if/for/while 語(yǔ)句中,即使執(zhí)行語(yǔ)句只有一句,也應(yīng)盡量另起一行。
4、不要在返回語(yǔ)句(return)或條件語(yǔ)句(if/for/while)中使用括號(hào),除非是用于實(shí)現(xiàn)行連接。
5、對(duì)于 if 語(yǔ)句, 在沒(méi)有 else 且語(yǔ)句比較短時(shí),可以在一行完成(但不推薦),比如:if foo: bar(foo).
6、對(duì)于簡(jiǎn)單的類定義,也可以在一行完成(但不推薦),比如定義一個(gè)異常:class UnfoundError(Exception): pass.
7、函數(shù)和方法的括號(hào)中使用垂直隱式縮進(jìn)或使用懸掛縮進(jìn)。
# 一行寫不下時(shí),有括號(hào)來(lái)連接多行,后續(xù)行應(yīng)該使用懸掛縮進(jìn) if (this_is_one_thing and that_is_another_thing): do_something() # 函數(shù)調(diào)用參數(shù)較多時(shí),對(duì)準(zhǔn)左括號(hào) f = foo(a, b, c, d) # 不對(duì)準(zhǔn)左括號(hào),但加多一層縮進(jìn),以和后面內(nèi)容區(qū)別 def long_function_name( a, b, c, d, e): print(a, b, c, d, e) # 列表、元組、字典以及函數(shù)調(diào)用時(shí)可以讓右括號(hào)回退,這樣更加美觀 l = [ 1, 2, 3, 4, 5, 6, ] result = some_function( "a", "b", "c", "d", "e", "f", )四、空格使用
總體原則,避免不必要的空格。
1、各種右括號(hào)前不要加空格。
2、逗號(hào)、冒號(hào)、分號(hào)前不要加空格,但應(yīng)該在它們后面加(除了在行尾)。
3、函數(shù)的左括號(hào)前不要加空格。如 Func(1)。
4、序列的左括號(hào)前不要加空格。如 list[2]。
5、操作符左右各加一個(gè)空格,不要為了對(duì)齊增加空格。
6、函數(shù)默認(rèn)參數(shù)使用的賦值符左右省略空格。
良好的風(fēng)格:
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)
不好的風(fēng)格:
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)五、注釋
總體原則,錯(cuò)誤的注釋不如沒(méi)有注釋。所以當(dāng)一段代碼發(fā)生變化時(shí),第一件事就是要修改注釋。注釋盡量使用英文,最好是完整的句子,首字母大寫,句后要有結(jié)束符,結(jié)束符后跟兩個(gè)空格,開(kāi)始下一句。如果是短語(yǔ),可以省略結(jié)束符。注釋應(yīng)該在 # 后加一個(gè)空格才開(kāi)始寫注釋內(nèi)容。
1、塊注釋,在一段代碼前增加的注釋。段落之間用只有 ‘#’ 的行間隔。比如:
# Description : Module config. # # Input : None # # Output : None
2、行注釋,在一句代碼后加注釋。應(yīng)該盡量在語(yǔ)句后空兩格后再開(kāi)始注釋。當(dāng)有連續(xù)的行注釋時(shí),為了美觀可以讓 ‘#’ 對(duì)齊。 在語(yǔ)句比較長(zhǎng)時(shí),應(yīng)該盡量少使用行注釋。比如:
person = { "name": "huoty", # 姓名 "age": 26, # 年齡 "stature": 169, # 身高 "weight": 60, # 體重 } print person # 輸出信息
3、對(duì)類或者函數(shù)的說(shuō)明,盡量不要在其定義的前一行或者后一行用塊注釋的形式來(lái)說(shuō)明,而應(yīng)該使用文檔字符串(docstring)
4、使用 TODO 注釋來(lái)標(biāo)記待完成的工作,團(tuán)隊(duì)協(xié)作中,必要的時(shí)候應(yīng)該寫上你的名字或者聯(lián)系方式,比如:
# TODO([email protected]): Use a "*" here for string repetition. # TODO(Huoty) Change this to use relations.
5、避免無(wú)謂的注釋。你見(jiàn)過(guò)哪些奇趣的代碼注釋?
# 你可能會(huì)認(rèn)為你讀得懂以下的代碼。但是你不會(huì)懂的,相信我吧。 # 要是你嘗試玩弄這段代碼的話,你將會(huì)在無(wú)盡的通宵中不斷地咒罵自己為什么會(huì)認(rèn)為自己聰明到可以優(yōu)化這段代碼。 # so,現(xiàn)在請(qǐng)關(guān)閉這個(gè)文件去玩點(diǎn)別的吧。 # 程序員1(于2010年6月7日):在這個(gè)坑臨時(shí)加入一些調(diào)料 # 程序員2(于2011年5月22日):臨你個(gè)屁啊 # 程序員3(于2012年7月23日):樓上都是狗屎,鑒定完畢 # 程序員4(于2013年8月2日):fuck 樓上,三年了,這坑還在!?。? # 程序員5(于2014年8月21日):哈哈哈,這坑居然坑了這么多人,幸好我也不用填了,系統(tǒng)終止運(yùn)行了,you"re died六、文檔描述
1、盡量為所有的共有模塊、函數(shù)、類、方法寫 docstring。
2、前三引號(hào)后不應(yīng)該換行,應(yīng)該緊接著在后面概括性的說(shuō)明模塊、函數(shù)、類、方法的作用,然后再空一行進(jìn)行詳細(xì)的說(shuō)明。后三引號(hào)應(yīng)該多帶帶占一行。比如:
"""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、函數(shù)和方法的 docstring 層次順序大致為概述、詳細(xì)描述、參數(shù)、返回值、異常,一般不要求描述實(shí)現(xiàn)細(xì)節(jié),除非其中涉及非常復(fù)雜的算法。大致的層次結(jié)構(gòu)如下所示:
"""函數(shù)或方法的概述 詳細(xì)的描述信息…… 詳細(xì)的描述信息…… 參數(shù)說(shuō)明 -------- 參數(shù)1:... 參數(shù)2:... 返回值: ... 異常: 異常1:... 異常2:... """
一個(gè)參考示例:
"""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 的層次順序大致為概述、詳細(xì)描述、屬性說(shuō)明。如果類有公開(kāi)屬性值時(shí),應(yīng)該盡量在 docstring 中進(jìn)行說(shuō)明。如下所示:
"""這里是類的概述。 詳細(xì)的描述信息…… 詳細(xì)的描述信息…… 屬性(Attributes): ----------------- 屬性1: ... 屬性2: ... """七、命名規(guī)范
1、模塊命名盡量短小,使用全部小寫的方式,可以使用下劃線。
2、包命名盡量短小,使用全部小寫的方式,不可以使用下劃線。
3、類的命名使用駝峰命令的方式,即單詞首字符大寫,類名應(yīng)該全部使用名詞。
4、異常命令應(yīng)該使用加 Error 后綴的方式,比如:HTTPError。
5、全局變量盡量只在模塊內(nèi)有效,并且應(yīng)該盡量避免使用全局變量。
6、函數(shù)命名使用全部小寫的方式,使用下劃線分割單詞,并采用動(dòng)賓結(jié)構(gòu)。
7、常量命名使用全部大寫的方式,使用下劃線分割單詞。
8、類的屬性(方法和變量)命名使用全部小寫的方式,使用下劃線分割單詞。
9、變量、類屬性等命令盡量不要使用縮寫形式,除了計(jì)數(shù)器和迭代器,盡量不要使用單字符名稱。
10、類的方法第一個(gè)參數(shù)必須是 self,而靜態(tài)方法第一個(gè)參數(shù)必須是 cls。
11、在模塊中要表示私有變量或者函數(shù)時(shí),可以在變量或者函數(shù)前加一個(gè)下劃線 _foo, _show_msg 來(lái)進(jìn)行訪問(wèn)控制。
12、在 Python 中沒(méi)有諸如 public、private、protected 等修飾符,而在類的定義中往往會(huì)有類似這樣的需求,那么可以在屬性或者方法前加一個(gè)下劃線表示 protected,加兩個(gè)下劃線來(lái)表示 private。加兩個(gè)下劃線的變量或者方法沒(méi)法直接訪問(wèn)。比如:類 Foo 中聲明 __a, 則不能用 Foo.__a 的方式訪問(wèn),但可以用 Foo._Foo__a 的方式訪問(wèn)。`
八、程序入口Python 屬于腳本語(yǔ)言,代碼的運(yùn)行是通過(guò)解釋器對(duì)代碼文件進(jìn)行逐行解釋執(zhí)行來(lái)完成的。它不像其他編程語(yǔ)言那樣有統(tǒng)一的入口程序,比如 Java 有 Main 方法,C/C++ 有 main 方法。Python 的代碼文件除了可以被直接執(zhí)行外,還可以作為模塊被其他文件導(dǎo)入。所有的頂級(jí)代碼在模塊導(dǎo)入時(shí)都會(huì)被執(zhí)行,當(dāng)希望模塊被導(dǎo)入時(shí),應(yīng)該避免主程序被執(zhí)行。這樣就需要把主程序放到 if __name__ == "__main__" 代碼塊中,比如:
def main(): ... if __name__ == "__main__": main()
一個(gè)包除了能夠被導(dǎo)入外,也可以通過(guò) python -m package 的方式被直接執(zhí)行,前提是包中需要有 __main__.py,這個(gè)文件可以說(shuō)是包的程序入口,包中有了這個(gè)文件就可以用 Python 的 -m 參數(shù)來(lái)直接運(yùn)行。
九、編碼建議1、盡可能使用 "is" 和 "is not" 取代 "==",比如 if x is not None 要優(yōu)于 if x != None,另外用 if x 效率更高。
Note: 等于比較運(yùn)算符(==) 會(huì)調(diào)用左操作數(shù)的 __eq__ 函數(shù),這個(gè)函數(shù)可以被其任意定義,而 is 操作只是做 id 比較,并不會(huì)被自定義。同時(shí)也可以發(fā)現(xiàn) is 函數(shù)是要快于等于運(yùn)算符的,因?yàn)椴挥貌檎液瓦\(yùn)行函數(shù)。
2、用 "is not" 代替 "not ... is",前者的可讀性更好。
3、使用基于類的異常,每個(gè)模塊或包都有自己的異常類,此異常類繼承自 Exception。
4、異常中盡量不要使用裸露的 except,except 后應(yīng)該跟具體的 exceptions。
5、使用 startswith() 和 endswith() 代替切片進(jìn)行序列前綴或后綴的檢查。
6、使用 isinstance() 比較對(duì)象的類型,而不是 type(),比如:
# Yes: if isinstance(obj, int) # No: if type(obj) is type(1)
7、判斷序列是否為空時(shí),不用使用 len() 函數(shù),序列為空時(shí)其 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、使用迭代器和生成器代替列表等數(shù)據(jù)結(jié)構(gòu)效率更高,使用列表(字典)解析式和生成器表達(dá)式比用循環(huán)效率更高。
13、避免在循環(huán)中用 + 或 += 來(lái)連續(xù)拼接字符串。因?yàn)樽址遣蛔冃?,這會(huì)毫無(wú)必要地建立很多臨時(shí)對(duì)象,從而成為二次方級(jí)別的運(yùn)算量而不是線性運(yùn)算時(shí)間。
14、多去了解標(biāo)準(zhǔn)庫(kù),標(biāo)準(zhǔn)庫(kù)中用很多好用的功能,能夠更優(yōu)雅的解決問(wèn)題,如 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/...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43096.html
摘要:原文介紹這篇文檔給出了語(yǔ)言編碼的風(fēng)格約定,包括中用實(shí)現(xiàn)的部分。譯者注不清楚這里是什么意思,括號(hào)中原文為語(yǔ)言版本使用標(biāo)準(zhǔn)年版本。這意味著在許多其他事情中所有聲明必須放在某個(gè)塊的頂部并不一定是函數(shù)的頂部。 原文http://legacy.python.org/dev/peps/pep-0007/ 介紹 這篇文檔給出了C語(yǔ)言編碼的風(fēng)格約定,包括Python中用C實(shí)現(xiàn)的部分。關(guān)于P...
摘要:原文作者原題的代碼庫(kù)使用編碼風(fēng)格。此外,推薦的用于連續(xù)行的編碼風(fēng)格毫無(wú)一點(diǎn)品味,絕不允許在代碼庫(kù)使用與開(kāi)局定界符對(duì)齊。但是,關(guān)于靈活設(shè)定行長(zhǎng)的部分,我舉雙手雙腳贊同。關(guān)于代碼風(fēng)格,沒(méi)有絕對(duì)完全一致的標(biāo)準(zhǔn)。 showImg(https://segmentfault.com/img/bVbnv2L?w=6000&h=4000); 原文:https://www.kennethreitz.or...
摘要:有一些定制類的特殊方法,如,其中一些具有動(dòng)態(tài)特性的方法可以用來(lái)很方便地處理某些動(dòng)態(tài)狀況。動(dòng)態(tài)化屬性和方法的調(diào)用,當(dāng)調(diào)用不存在的屬性時(shí),如果存在方法,就會(huì)調(diào)用方法來(lái)嘗試獲得屬性。這種完全動(dòng)態(tài)的調(diào)用可以應(yīng)對(duì)一些動(dòng)態(tài)情況,例如實(shí)現(xiàn)。 Python有一些定制類的特殊方法,如__str__()、__iter__()、__getitem__(),其中一些具有動(dòng)態(tài)特性的方法可以用來(lái)很方便地處理某些動(dòng)...
閱讀 779·2019-08-29 16:32
閱讀 847·2019-08-29 12:31
閱讀 3231·2019-08-26 18:26
閱讀 3169·2019-08-26 12:20
閱讀 1744·2019-08-26 12:00
閱讀 3015·2019-08-26 10:58
閱讀 2822·2019-08-23 17:08
閱讀 2318·2019-08-23 16:32