代碼布局
縮進
推薦的兩種方式:
- 垂直對齊:與(), [], {}對齊
- 懸掛縮進
建議
# 垂直對齊嘶炭,與外面(), [], {}對齊
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 懸掛縮進得运,以行開頭作為參考
foo = long_function_name(
var_one, var_two,
var_three, var_four)
# 為了和函數(shù)體區(qū)分開蟹漓,采用更多的縮進
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
不建議
# 如果使用懸掛縮進而不是垂直對齊链快,第一行就不要有參數(shù)铣耘。
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)
括號結束的處理
- 可以在最后一個元素后面
- 可以和語句開頭第一個字符對齊
- 可以和上一行第一個不為空格的字符對齊
# 和上一行的第一個不為空格的字符對齊
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
# 和語句開頭的第一個字符對齊
my_list = [
1, 2, 3,
4, 5, 6,
]
if語句的縮進
# 無額外的縮進.
if (this_is_one_thing and
that_is_another_thing):
do_something()
# 添加一條注釋來分隔if語句的兩個部分
# supporting syntax highlighting.
if (this_is_one_thing and
that_is_another_thing):
# Since both conditions are true, we can frobnicate.
do_something()
# 添加額外的縮進來分隔if語句的兩個部分
if (this_is_one_thing
and that_is_another_thing):
do_something()
Tab
還是空格
- 推薦使用空格
- 只有在兼容的時候使用
Tab
-
Python 3
不允許兩者混合使用诺苹。 -
Python 2
用選項-t
可以在混合使用的時候發(fā)出警告抛姑;使用選項-tt
會發(fā)出錯誤卓嫂。
單行的最大長度
79個字符。
對于docstring
和注釋: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())
換行到底在二元操作符前面還是后面紧卒?
# No: operators sit far away from their operands
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
# Yes: easy to match operators with operands
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
空行
- 頂層的函數(shù)侥衬、類用兩個空行分隔
- 類內部的方法定義用一個空行分隔
- 在函數(shù)內部使用空行表示邏輯的分塊
- 可以使用
control-L
作為換頁符,貌似pycharm并不支持
文件編碼
UTF-8
import
語句
- 分開使用
# Yes:
import os
import sys
# No:
import sys, os
# OK:
from subprocess import Popen, PIPE
- 在文件最上方:模塊注釋和
docstring
之后跑芳,globals
和常量之前轴总。順尋應該是(每組之間用空行隔開):- 標準庫
- 相關的第三方庫
- 本地庫
- 導入一個類時:
from myclass import MyClass
from foo.bar.yourclass import YourClass
# 如果類名有沖突
import myclass
import foo.bar.yourclass
# 使用時:"myclass.MyClass" "foo.bar.yourclass.YourClass".
- 盡量避免
import mypkg.*
。
模塊級的dunder name
模塊級的dunder name博个,比如__all__, __version__, __author__
應該放在import
之前怀樟,但是在from __future__ import
之后,因為這一句是強制要求在所有代碼之前的盆佣。
"""This is the example module.
This module does stuff.
"""
from __future__ import barry_as_FLUFL
__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
字符串的引號
單引號雙引號都可以往堡,那么選擇一個,然后保持一致共耍。
表達式和語句中的空格
一定不要這么做虑灰!
- 括號內,緊挨括號的地方痹兜,不要加空格
# Yes:
spam(ham[1], {eggs: 2})
foo = (0,)
# No:
spam( ham[ 1 ], { eggs: 2 } )
bar = (0, )
-
, ; :
之前穆咐,不要加空格
# Yes:
if x == 4: print x, y; x, y = y, x
# No:
if x == 4 : print x , y ; x , y = y , x
- 在切片中使用
:
的時候,把它當作一個操作符來考慮:兩邊使用同樣多的空格字旭。例外:如果切片中有的參數(shù)省略了庸娱,那么該參數(shù)的空格也要省略
# Yes:
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]
# No:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
- 參數(shù)列表的小括號
(
之前,不要加空格
# Yes:
spam(1)
foo = (0, 1)
# No:
spam (1)
- 索引或切片操作的中括號
[
之前谐算,不要加空格
# Yes:
dct['key'] = lst[index]
# No:
dct ['key'] = lst [index]
- 賦值操作符前后只要一個空格,不要用過多的空格來對齊
# Yes:
x = 1
y = 2
long_variable = 3
# No:
x = 1
y = 2
long_variable = 3
其他的建議
- 行尾不要有空格
- 為下列二維操作符的前后各加一個空格:賦值归露、比較洲脂、
booleans
。 - 在同一句語句中剧包,可以省略優(yōu)先級較高的操作符之間的空格恐锦。二元操作符前后的數(shù)量一定要相等,一定不要超過一個疆液。
- 關鍵字參數(shù)和默認參數(shù)中的
=
前后不要加空格
# 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)
- 函數(shù)和參數(shù)的注解:冒號
:
前無空格一铅,后跟空格;->
前后各一個空格堕油;既有注解又有默認值時潘飘,等號=
前后各一個空格肮之。
# Yes:
def munge(sep: AnyStr = None): ...
def munge() -> AnyStr: ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# No:
def munge(input: AnyStr=None): ...
def munge()->PosInt: ...
def munge(input: AnyStr, limit = 1000): ...
什么時候使用結尾的逗號
- 只有一個元素的tuple。這種情況最好使用括號卜录。
# Yes:
FILES = ('setup.cfg',)
# OK
FILES = 'setup.cfg',
- 在一個值占一行戈擒,且右括號
)]}
單獨占一行的情況,可以加一個多于的逗號在句尾艰毒】鸶撸可以方便diff
。
# Yes:
FILES = [
'setup.cfg',
'tox.ini',
]
initialize(FILES,
error=True,
)
# No:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)
注釋
- 不要與代碼矛盾丑瞧!改代碼也要改注釋
- 塊注釋必須由完整的句子組成柑土,用句號分隔
- 最好用英文
行內注釋
- 不要太多
- 與語句至少2個空格,
#
后跟一個空格绊汹。
文檔字符串 docstrings
- 為公共的模塊稽屏、函數(shù)、類灸促、方法寫注釋诫欠。
- 格式
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
命名規(guī)范
讓所有代碼都遵守一致的命名規(guī)范很難的,可以要求新的模塊和包遵守一定的規(guī)范浴栽,但已有的庫可能不滿足荒叼,這時候需要在內部保持一致。
首要原則
對外的接口典鸡,要反映usage被廓,而不是implementation
常見的命名方式
- b
- B
- lowercase
- lower_case_with_underscores
- UPPERCASE
- UPPER_CASE_WITH_UNDERSCORES
- CapitalizedWords
- mixedCase
- Capitalized_Words_With_Underscores
Python中的一些約定 - _single_leading_underscore
- single_trailing_underscore_
- __double_leading_underscore
- __double_leading_and_trailing_underscore__
規(guī)范
- 模塊名:小寫字母+下劃線
- 包名:小寫字母。
e.g. timeit
- 類名:首字母大寫萝玷。
e.g. CapWords
- 異常名:首字母大寫+后綴
Error
- 函數(shù)名嫁乘、變量名、方法名球碉、實例變量名:小寫+下劃線
- 參數(shù)名:小寫+下劃線蜓斧;
self
和cls
是約定;與關鍵字沖突的時候睁冬,在后面加_
- 常量:大寫字母+下劃線
繼承的設計
- 公共屬性不要以下劃線開頭挎春。
- 如果屬性與關鍵字沖突,在結尾地方加一個下劃線豆拨。
- 對public的數(shù)據(jù)屬性直奋,最好不要getter/setter(accessor/mutator)方法。
- 如果有屬性不想讓子類使用施禾,則命名為
__foo
脚线,觸發(fā)python的命名轉換。
公共接口和內部接口
- 必須保證公共接口向后兼容弥搞,對內部接口則不用
- 必須為公共借口提供文檔
- 使用all聲明公共接口
- 內部接口(包邮绿、模塊渠旁、類、函數(shù)等)使用前綴
_
編程建議
- 不要依賴與具體的python實現(xiàn)(PyPy, Jython, IronPython, Cython)
- 與單例對象(比如
None
)作比較的時候斯碌,用is
和is not
一死,而不是==
。 - 使用
is not
而不是not ... is
傻唾。
# Yes:
if foo is not None:
...
# No:
if not foo is None:
...
- 使用
def
投慈,而不是賦值+lambda
。 -
python2
中冠骄,用raise ValueError('message')
代替raise ValueError, 'message'
伪煤。后者在python3
是錯誤的。 - 為
expect
指明異常類型凛辣,需要異常名時抱既,使用as
。
try:
foo()
expect Exception as exc:
print(exc)
-
try
語句塊內的語句盡可能的少扁誓。 - 局部使用的資源防泵,使用
with
。
自動格式化的工具
black
- 基于
python3
蝗敢,可以格式化python2
的代碼 - 比較專制捷泞,遵守
pep8/pycodestyle
- 默認全部使用雙引號(為啥?)寿谴,可以用選項--skip-string-normalization來跳過锁右,不更改字符串的引號。
- 在列表最后項的末尾加了多于的逗號
,
- 去除不必要的反斜杠
\
- 過長的字符串不做處理
- 列表太多太長時:一項獨占一行
- 用
# fmt: off
和# fmt: on
來標記不需要format的語句塊讶泰,兼容yapf
的標記咏瑟。 - make
pycodestyle
happy.PEP8
的子集 - 在二元操作符前換行
- 切片:
PEP8
如何處理折行?
1. 嘗試不折行
2. 打開最外層括號痪署,括號內內容單獨一行
3. 還是不行码泞,迭代打開括號
4. 如果內容沒有括號,有逗號做分隔狼犯,嘗試同一行
5. 放不下->每一項獨占一行余寥,并加一個多于的逗號。(便于diff)
# in:
def very_important_function(template: str, *variables, file: os.PathLike, debug: bool = False):
"""Applies `variables` to the `template` and writes to `file`."""
with open(file, 'w') as f:
...
# out:
def very_important_function(
template: str,
*variables,
file: os.PathLike,
debug: bool = False,
):
"""Applies `variables` to the `template` and writes to `file`."""
with open(file, "w") as f:
...
行的長度
默認88辜王,為了讓文件長度更短。
尺有所短寸有所長罐孝。
空行
遵循PEP8
呐馆。
- 在函數(shù)前后插入一個空行,在模塊級的類和函數(shù)的前后插入兩個空行莲兢。
- 類的
docstrings
后緊跟一個空行 - 函數(shù)的
docstrings
后一般不跟空行汹来,除非后面緊跟一個內部函數(shù)续膳。
tailing commas
- 在獨占一行的時候添加
isort
自動給import
語句排序。
靜態(tài)代碼分析工具
pycodestyle
原名pep8收班。參照PEP 8坟岔。定義了Error codes。
Pylint
flake8
formatter
yapf
black
- “驕傲”
autopep8
- 使用
pycodestyle
來決定需要格式化的代碼摔桦,修復它報的大部分格式問題社付。 - 默認,只做空格空行的增減邻耕,不會修正
x == None
鸥咖。加選項--agressive
。 -
--select
修正指定的錯誤/警告兄世。 - 可以作為模塊使用啼辣。
- 以
PEP 8
和pycodestyle
為導向