Python代碼風(fēng)格檢查與格式化
參考資料
-
Google
代碼規(guī)范:https://www.runoob.com/w3cnote/google-python-styleguide.html
依賴包安裝
pip install flake8 -i https://pypi.douban.com/simple # 代碼檢查工具
pip install yapf -i https://pypi.douban.com/simple # Google開(kāi)源的Python格式化工具
常用規(guī)則
代碼頭部:程序的
main
文件應(yīng)該以#!/usr/bin/python2
或者#!/usr/bin/python3
開(kāi)始始腾。#!
先用于幫助內(nèi)核找到Python
解釋器, 但是在導(dǎo)入模塊時(shí), 將會(huì)被忽略. 因此只有被直接執(zhí)行的文件中才有必要加入#!
.-
一行代碼過(guò)長(zhǎng)時(shí)的處理
- 括號(hào)內(nèi)的參數(shù)很多的時(shí)候, 為了滿足每一行的字符不超過(guò)79個(gè)字符,
- 需要將參數(shù)換行編寫, 這個(gè)時(shí)候換行的參數(shù)應(yīng)該與上一行的括號(hào)對(duì)齊.
- 或者將所有參數(shù)換行編寫, 此時(shí)第一行不能有參數(shù),
- 即第一行的最后一個(gè)字符一定要是(, 換行后需要有一個(gè)縮進(jìn).
- 類似的規(guī)則也用在[], {}上.
命名規(guī)則
- 應(yīng)避免的命名
單字符名稱, 除了計(jì)數(shù)器和迭代器.
包/模塊名中的連字符(-)
雙下劃線開(kāi)頭并結(jié)尾的名稱(Python保留, 例如__init__)
- 命名約定
所謂"內(nèi)部(Internal)"表示僅模塊內(nèi)可用, 或者, 在類內(nèi)是保護(hù)或私有的.
用單下劃線(_)開(kāi)頭表示模塊變量或函數(shù)是protected的(使用import * from時(shí)不會(huì)包含).
用雙下劃線(__)開(kāi)頭的實(shí)例變量或方法表示類內(nèi)私有.
將相關(guān)的類和頂級(jí)函數(shù)放在同一個(gè)模塊里. 不像Java, 沒(méi)必要限制一個(gè)類一個(gè)模塊.
對(duì)類名使用大寫字母開(kāi)頭的單詞(如CapWords, 即Pascal風(fēng)格), 但是模塊名應(yīng)該用小寫加下劃線的方式(如lower_with_under.py). 盡管已經(jīng)有很多現(xiàn)存的模塊使用類似于CapWords.py這樣的命名, 但現(xiàn)在已經(jīng)不鼓勵(lì)這樣做, 因?yàn)槿绻K名碰巧和類名一致, 這會(huì)讓人困擾.
- Python之父Guido推薦的規(guī)范
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 | - |
導(dǎo)入格式
- 每個(gè)導(dǎo)入應(yīng)該獨(dú)占一行
- 導(dǎo)入總應(yīng)該放在文件頂部, 位于模塊注釋和文檔字符串之后, 模塊全局變量和常量之前. 導(dǎo)入應(yīng)該按照從最通用到最不通用的順序分組:
標(biāo)準(zhǔn)庫(kù)導(dǎo)入
第三方庫(kù)導(dǎo)入
應(yīng)用程序指定導(dǎo)入
- 每種分組中, 應(yīng)該根據(jù)每個(gè)模塊的完整包路徑按字典序排序, 忽略大小寫
import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar
函數(shù)定義
- 文檔字符串應(yīng)該包含函數(shù)做什么, 以及輸入和輸出的詳細(xì)描述. 通常, 不應(yīng)該描述"怎么做", 除非是一些復(fù)雜的算法. 文檔字符串應(yīng)該提供足夠的信息, 當(dāng)別人編寫代碼調(diào)用該函數(shù)時(shí), 他不需要看一行代碼, 只要看文檔字符串就可以了. 對(duì)于復(fù)雜的代碼, 在代碼旁邊加注釋會(huì)比使用文檔字符串更有意義.
- 函數(shù)和方法注釋說(shuō)明材失。如果一個(gè)函數(shù)接受
*foo
(可變長(zhǎng)度參數(shù)列表)或者**bar
(任意關(guān)鍵字參數(shù)), 應(yīng)該詳細(xì)列出*foo
和**bar
- 規(guī)則:
Args:
列出每個(gè)參數(shù)的名字, 并在名字后使用一個(gè)冒號(hào)和一個(gè)空格, 分隔對(duì)該參數(shù)的描述.如果描述太長(zhǎng)超過(guò)了單行80字符,使用2或者4個(gè)空格的懸掛縮進(jìn)(與文件其他部分保持一致). 描述應(yīng)該包括所需的類型和含義. 如果一個(gè)函數(shù)接受*foo(可變長(zhǎng)度參數(shù)列表)或者**bar (任意關(guān)鍵字參數(shù)), 應(yīng)該詳細(xì)列出*foo和**bar.
Returns: (或者 Yields: 用于生成器)
描述返回值的類型和語(yǔ)義. 如果函數(shù)返回None, 這一部分可以省略.
Raises:
列出與接口有關(guān)的所有異常.
- 示例:
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""Fetches rows from a Bigtable.
Retrieves rows pertaining to the given keys from the Table instance
represented by big_table. Silly things may happen if
other_silly_variable is not None.
Args:
big_table: An open Bigtable Table instance.
keys: A sequence of strings representing the key of each table row
to fetch.
other_silly_variable: Another optional variable, that has a much
longer name than the other args, and which does nothing.
Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings. For
example:
{'Serak': ('Rigel VII', 'Preparer'),
'Zim': ('Irk', 'Invader'),
'Lrrr': ('Omicron Persei 8', 'Emperor')}
If a key from the keys argument is missing from the dictionary,
then that row was not found in the table.
Raises:
IOError: An error occurred accessing the bigtable.Table object.
"""
pass
類定義
- 類應(yīng)該在其定義下有一個(gè)用于描述該類的文檔字符串. 如果你的類有公共屬性
(Attributes)
, 那么文檔中應(yīng)該有一個(gè)屬性(Attributes)
段. 并且應(yīng)該遵守和函數(shù)參數(shù)相同的格式.
class SampleClass(object):
"""Summary of class here.
Longer class information....
Longer class information....
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def __init__(self, likes_spam=False):
"""Inits SampleClass with blah."""
self.likes_spam = likes_spam
self.eggs = 0
def public_method(self):
"""Performs operation blah."""
- 如果一個(gè)類不繼承自其它類, 就顯式的從
object
繼承
class SampleClass(object):
pass
- 如果訪問(wèn)更復(fù)雜, 或者變量的訪問(wèn)開(kāi)銷很顯著, 那么你應(yīng)該使用像
get_foo()
和set_foo()
這樣的函數(shù)調(diào)用. 如果之前的代碼行為允許通過(guò)屬性(property)
訪問(wèn) , 那么就不要將新的訪問(wèn)函數(shù)與屬性綁定. 這樣, 任何試圖通過(guò)老方法訪問(wèn)變量的代碼就沒(méi)法運(yùn)行, 使用者也就會(huì)意識(shí)到復(fù)雜性發(fā)生了變化.
注釋
- TODO:TODO注釋應(yīng)該在所有開(kāi)頭處包含"TODO"字符串, 緊跟著是用括號(hào)括起來(lái)的你的名字, email地址或其它標(biāo)識(shí)符. 然后是一個(gè)可選的冒號(hào). 接著必須有一行注釋, 解釋要做什么.
# TODO(kl@gmail.com): Use a "*" here for string repetition.
# TODO(Zeke) Change this to use relations.