也算是用了一段時間的python了,但是想要符合python的代碼規范pep-8那可是必須讀的。
Indentation
縮進是python的一大特點,對于每一個段落(level)的縮進,pep-8給出的規范是4 spaces。有的編輯器默認是8 spaces的,建議修改一下。
對于那些個hanging indents應該視為一個level添加縮進。你可以這樣:
#python的縮進可以讓代碼更readable
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
foo = long_function_name(var_one, var_two,
var_three, var_four)
foo = long_function_name(
var_one, var_two,
var_three, var_four)
但是要避免下面的寫法:
#WARNING
foo = long_function_name(var_one, var_two,
var_three, var_four)
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
對于} ] )
這樣的閉合符號如果跨過了多行怎么辦?
你可以對齊元素的level:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
也可以對齊該結構的level:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
Tabs or Spaces?
pep-8是這么說的:
Spaces 是首選的縮進方法,Tabs只應該被用在保持用Tabs縮進的段落之間一致性上。
不管是那個,不要混合使用!
Maximum Line Length
一行最多能擺多少字符,嗯...應該是79個。如果是文檔注釋一類的限制則為72個字符。
你可以用\來在下一行延續你的代碼,當然更歡迎使用括號來包裹你的表達式進行換行。
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
當然在換行過后要確保適當的縮進。
Should a line break before or after a binary operator?
在操作符前換行或者在操作符后面換行。python的特點是readable,所以建議這樣寫:
# Yes: easy to match operators with operands
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
當然也不是不可以在操作符后面換行,但是要注意保持一致性。
Blank Lines
空白行怎么用?
- top-level function和class之間兩空兩行。
- 類內的方法的定義之間空一行。
- 在方法中使用空白行作為邏輯區分
- 其他地方盡量不要再空行。
Source File Encoding
- 盡量使用UTF-8(或者 ASCII in python2)。
- 對于使用ASCII碼的python2文件或者使用UTF-8的python3文件,不要進行編碼聲明。
- 所有的標準庫里的標識符都必須使用ASCII編碼,并且在可以使用英文的時候盡量使用英文。唯一的一些例外是測試用例和你的名字。開源的項目更鼓勵這樣做(嗯,應該在來個中文版...)。
- 不是默認的編碼只能用在測試或者注釋里。
Imports
imports應該分行寫,from something import ...
例外:
Yes: import os
import sys
No: import sys, os
imports應該放在文件的頂部,在模塊注釋和文檔字符串后面,在全局變量和常量之前。
imports還應該按照如下順序分組:
- 標準庫的imports
- 第三方部分的imports
- 本地聲明的imports
- 在每一類imports之間你應該空一行。
把任何有關all的說明放到imports的后面。
Absolute imports or Explicit imports
推薦完全引入,它們更可讀也更可靠。
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
不過,相對引入也可用于替代絕對完全引入特別是處理復雜的包時完全引入會造成不必要的冗長。
from .import sibling
from .sibling import example
對于標準庫的imports必須使用完全引入。要避免from <module> import *
這樣的寫法,這樣會帶來混淆,對于包的名稱要明確并且做好區分,方便管理。
Whitespace in Expressions and Statements
表達式和語句中的空格怎么用?
下面的情況應該避免多余的空格:
- 緊挨著各種括號應該這么寫:
Yes: spam(ham[1], {eggs: 2})
- 后面緊跟著逗號、分號或者冒號:
Yes: if x == 4: print x, y; x, y = y, x
- 緊挨著調用函數括號:
Yes: spam(1)
- 序列的左括號后不要加空格:
Yes: dct['key'] = lst[index]
- 在任何行尾不要使用空格。
其他空格:
- 在這些個操作符的兩邊都使用一個空格:
assignment (=), augmented assignment (+=,-=etc.), comparisons (==,<,>,!=,<>,<=,>=,in,not in,is,is not), Booleans (and,or,not).
- 在不同優先級的操作符之間可以考慮添加空格(建議實在優先級低的一邊),二元操作符兩邊使用相同的空格數,不要超過一個
- 切片里的冒號感覺像一個二元操作符,它的兩邊應該留有相同個數的空格,如果切片中有擴展冒號,使用相同的格式。當然如果冒號的參數被省略,那么空格也省略:
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
- 操作符左右各加一個空格使它們對齊(但是不要強行對齊):
x = 1
y = 2
long_variable = 3
- 在函數定義中的參數默認值和key值所使用的=號兩邊不要添加空格:
def complex(real, imag=0.0):
- 不鼓勵使用組合語句,也就是盡量不用 ; 組合,該分行的時候就分行。
- 在
if / for / while
語句塊中,該分行就分行,即使只有一行。
Comments
哈哈,這個跟hello world
基本上出現頻率相同的東西又來啦——注釋。
- 誤導人的注釋有了不如沒有,所以記得更新你的注釋。
- 在你的注釋里不要改變表示符的寫法,make it readable。并且要讓你的注釋是一個大寫開頭 句號結尾 的完整的句子。
- 在每個句子結束的時候應該用兩個空格。
- 中國的朋友請用英語編寫注釋,除非你120%的肯定不會有老外看...
Python coders from non-English speaking countries: please write your comments in English, unless you are 120% sure that the code will never be read by people who don't speak your language.
其實我想說:
Python coders from English speaking countries: please write your comments in Chinese, unless you are 120% sure that the code will never be read by people who just speak Chinese.
好吧純屬玩笑啦。
Block Comments:塊注釋,用于注釋跟著它的那些個代碼,注釋應該和備注釋的代碼處于同一個level,使用一個#和一個空格開始,如果要分段的話,使用只有#的空白行注釋分割。
Inline Comments:行注釋,再需要的時候使用,做一些適當的說明。使用一個#和一個空格。
Documentation Strings:文檔字符串,你應該為每一個公共的模塊,函數,類,方法寫一個文檔字符串,非public的函數也許不需要文檔字符,但是你應該在它的def
之后給他寫一個注釋。在變寫文檔字符的時候也要保持"""的縮進。
Version Bookkeeping
版本聲明,在你的source file里面添加:__version__ = "$Revision: 9afe77ad549b $"
這行代碼應該緊跟在文檔字符串后面。
Naming Conventions
命名規范。先來一看一看:
The naming conventions of Python's library are a bit of a mess, so we'll never get this completely consistent -- nevertheless, here are the currently recommended naming standards. New modules and packages (including third party frameworks) should be written to these standards, but where an existing library has a different style, internal consistency is preferred.
一般有這么幾種命名格式:
- b(single lowercase letter)
- B(single uppercase letter)
- lowercase
- lower_case_with_underscores
- UPPERCASE
- UPPER_CASE_WITH_UNDERSCORES
- CapitalizedWords(or CapWords, or CamelCase )
Note: When using abbreviations in CapWords, capitalize all theletters of the abbreviation. Thus HTTPServerError is better thanHttpServerError. - mixedCase
(differs from CapitalizedWords by initial lowercasecharacter!) - Capitalized_Words_With_Underscores (ugly!)
python變量中的公認的下劃線使用方法:
-
_single_leading_underscore
弱“內部使用”指標。用from module import *
的方式不能導入這樣的對象。 -
single_trailing_underscore_
通過_
后綴避免與Python關鍵字的沖突,例如Tkinter.Toplevel(master, class_='ClassName')
-
__double_leading_underscore
當命名類屬性的時候,使得(類foobar
內的__boo成為_foobar__boo
;這是python的名稱修改機制見下文) -
__double_leading_and_trailing_underscore__
“奇妙”的對象或者屬性,不要發明這樣的名字,用文檔里面定義好的。 - 在python中很少使用統一前綴來表示有相近關系的變量
命名規定:
-
Names to Avoid:不要單獨使用
l O I
這幾個字母作為變量名。 -
Package and Module Names:模塊命名盡量短小,使用全部小寫的方式,可以使用下劃線。包命名盡量短小,使用全部小寫的方式,不可以使用下劃線。C/C++的擴展用到python的話命名使用
_modulename
的方式。 - Class Names:類的命名使用ClassName的方式,模塊內部使用的類采用_ClassName的方式。
- Exception Names:異常命名使用CapWords+Error后綴的方式。
- Function Names:函數命名使用全部小寫的方式,可以使用下劃線。
- Global Variable Names:全局變量命名使用函數的命名方式。實現單模板的全局變量方法有兩種,一是在其他模板導入時使用all機制;二是前綴一個下劃線(即將變量視為模板非公開)。
-
Function and method arguments:函數和方法的變量名稱的命名,
self,cls
分別對應實例方法和類方法的第一個參數 。如果參數與關鍵字重名,在最后加一個下劃線。 - Constants:常量通常定義在模塊層,常量命名使用全部大寫的方式,可以使用下劃線。
-
Method Names and Instance Variables:方法名稱和實例變量的命名規則和函數的命名規則一致。還應注意:
- 如果是非公的方法或者實體在命名前面加上一個下劃線。
- 為了避免子類父類命名沖突,用兩個前綴下劃線調用python的名稱改寫機制。
- 這里是原文的引用:
Use one leading underscore only for non-public methods and instance variables.
To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.
Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
Designing for inheritance
提供面向對象的語言都涉及繼承的設計,python也不例外。
在設計之初一定要決定類的方法和實例變量應該是公有的還是非公的,如果還沒有決定,那就先設為非公的,因為從非公到公的轉化比從公到非公的轉化簡單,改得時候方便。
python里省略了private,python中沒有真正意義上的private變量,這樣使事情變得輕松不少。
還有一種屬性是作為“子類的API”存在的(其他語言稱為protect的屬性)。有些類生來就是要被繼承的,在子類中做些擴展改變一下類的方法行為,在設計這樣的類的時候,明確的決定好哪些屬性是公有的,哪些是作為子類的API的,哪些是只用與基類的。
With this in mind, here are the Pythonic guidelines:
- 公有的屬性名不要有前綴下劃線
- 如果你的共有的屬性名字與保留的關鍵字沖突,最好縮寫一下。 (However, notwithstanding this rule, 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method.)
- 對于簡單的數據屬性,簡單明了的命名就好。
- 如果你的類要派生子類,并且你有不想讓子類訪問的類型,考慮將它們使用雙下劃線前綴并且沒有后綴下劃線的方式命名,這會調用python的名稱改寫算法。這可以幫助你避免子類不小心出現和父類同名屬性而產生的問題。
- 只有單繼承有這樣的機制,如果一個子類選擇了同名的class和同名的屬性名,還是會有沖突。
- 名稱改寫機制會讓一些工作變得不是很方便,比如調試和
__getarr()__
,然而記錄和易于手動執行。 - 不是每個人都喜歡名稱改寫。
Public and internal interfaces
公共和內部接口。
模塊應該用一個__all__
顯示的聲明它的公開接口,文檔化的接口如果在文檔內部沒有說明那么它應該是一個公共接口。
內部的接口在名字前面加上_
。
__author__=='xuehao'
在下初入python,如果內容有差錯,還請大家指出。
email:darkframexue@outlook.com