規(guī)范修煉-PEP8規(guī)范解讀
當(dāng)你的老大讓你去修改別人的代碼時(shí),當(dāng)你懷著熱切的心情打開代碼定睛一瞧,縮進(jìn)錯(cuò)亂,命名不規(guī)范,通篇沒注釋,你是不是有那木一刻非常想提起四十米的大刀大喊一聲:狗賊,來吃灑家一刀!!!
因代碼不規(guī)范,碼農(nóng)槍擊4名同事的事件真的在美國出現(xiàn)過.
為了防止世界被破壞,為了守護(hù)世界的和平,呸呸呸,串臺(tái)了。咱吧,也不為別的,就為了把代碼寫的漂亮整潔,讓同事一看,嚯,這代碼真靚。
有句笑話是這樣講的:代碼寫的好的人,離職后找個(gè)人很快就能接手代碼,而代碼寫的亂的人則是公司的不可替代人才!為何叫不可替代人才呢,自己寫的代碼回頭看一看自己都看不懂,這境界就叫做不可替代。
因此我們需要非常重視編程規(guī)范?那么什么是編程規(guī)范,又都有哪些呢?
1.編程規(guī)范指的是什么
編程規(guī)范,指的是一組規(guī)則或指導(dǎo)意見,建議你,要求你,在編程時(shí),用某種計(jì)算機(jī)語言寫代碼時(shí),如何寫,要遵循什么意見或建議。
一般來說,不是強(qiáng)制的,但是是多數(shù)人都遵守的一些規(guī)范。
不過,很多公司,倒是強(qiáng)制性的,使用統(tǒng)一的某種規(guī)范,此時(shí),此規(guī)范或約定,就是要強(qiáng)制性的實(shí)行了。
在討論編程規(guī)范時(shí),另外還有幾個(gè)常提到的概念,在此處可以理解基本上是同一個(gè)意思:
- 編程約定Coding Convention(s)
- 編程規(guī)范Coding Rule(s)
- 編程風(fēng)格Coding Style(s)
- 編碼標(biāo)準(zhǔn)Coding Standard(s)
2.編程規(guī)范有哪些
- 不同編程語言有自己的編程規(guī)范
- 不同公司或組織有自己的編程規(guī)范
- PEP8解讀
- google規(guī)范解讀
規(guī)范里面大部分是 不要做的項(xiàng)多, 要做的比較少, 落地比較容易
代碼最主要的不是性能,而是可讀性, 有了可讀性才有維護(hù)性
我覺得我的編碼習(xí)慣比技術(shù)更有價(jià)值
程序猿不招妹子們喜愛的根本原因在于程序員追求了錯(cuò)誤的目標(biāo):更短、更小、更快。
3.PEP8解讀
python官網(wǎng)PEP8文檔地址:https://www.python.org/dev/peps/pep-0008/
1. 什么是PEP?
PEP是 Python Enhancement Proposal 的縮寫,翻譯過來就是 Python增強(qiáng)建議書 。
PEP8譯者:本文基于 2013-08-02 最后修改的 PEP8 版本翻譯,若要查看英文原文,請(qǐng)參考PEP8
然而,有時(shí)候編碼規(guī)范的建議并不適用。
許多項(xiàng)目都有一套專有的編碼風(fēng)格指南,當(dāng)沖突發(fā)生時(shí),應(yīng)以項(xiàng)目編碼規(guī)范為優(yōu)先。
特別是不要為了遵守PEP約定而破壞兼容性!
當(dāng)以下情況發(fā)生時(shí),也是忽略某個(gè)風(fēng)格指南的好理由:
- 當(dāng)遵守規(guī)范會(huì)降低代碼可讀性,甚至對(duì)于那些依循 PEP 去閱讀代碼的人也是這樣時(shí)。
- 當(dāng)遵守規(guī)范會(huì)與其他部分的代碼風(fēng)格背離時(shí) — 當(dāng)然也許這是一個(gè)修正某些混亂代碼的機(jī)會(huì)。
- 當(dāng)那些并沒有遵循規(guī)范的舊代碼已無法修改時(shí),而且也沒有充足的理由去修改他們。
- 當(dāng)你的代碼需要與舊版本的 Python 保持兼容,而舊版本的 Python 不支持規(guī)范中提到的特性時(shí)。
2.PEP8的主要內(nèi)容
- 代碼布局
- 字符串引號(hào)
- 表達(dá)式與空格
- 注釋的使用
- 文檔描述
- 命名規(guī)范
- 編碼建議
3. 代碼布局
1. 縮進(jìn)
每一級(jí)縮進(jìn)使用4個(gè)空格。
續(xù)行應(yīng)該與其包裹元素對(duì)齊,要么使用圓括號(hào)、方括號(hào)和花括號(hào)內(nèi)的隱式行連接來垂直對(duì)齊,
? 要么使用掛行縮進(jìn)對(duì)齊
- 當(dāng)使用掛行縮進(jìn)時(shí),應(yīng)該考慮到第一行不應(yīng)該有參數(shù),以及使用縮進(jìn)以區(qū)分自己是續(xù)行。
不推薦:
# 沒有使用垂直對(duì)齊時(shí),禁止把參數(shù)放在第一行
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 當(dāng)縮進(jìn)沒有與其他行區(qū)分時(shí),要增加縮進(jìn)
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
推薦:
# 與左括號(hào)對(duì)齊
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 用更多的縮進(jìn)來與其他行區(qū)分
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# 掛行縮進(jìn)應(yīng)該再換一行
foo = long_function_name(
var_one, var_two,
var_three, var_four)
- 掛行縮進(jìn)不一定要用4個(gè)空格
# 掛行縮進(jìn)不一定要用4個(gè)空格
foo = long_function_name(
var_one, var_two,
var_three, var_four)
- 當(dāng)if語句的條件部分長(zhǎng)到需要換行寫的時(shí)候,注意可以在兩個(gè)字符關(guān)鍵字的連接處(比如if),增加一個(gè)空格,再增加一個(gè)左括號(hào)來創(chuàng)造一個(gè)4空格縮進(jìn)的多行條件。這會(huì)與if語句內(nèi)同樣使用4空格縮進(jìn)的代碼產(chǎn)生視覺沖突。對(duì)于如何(或是否)在視覺上進(jìn)一步將這些條件行與
if語句內(nèi)的嵌套套件區(qū)分開,PEP不做任何明確的表述??墒褂玫倪x項(xiàng)包括但不限于下面幾種情況:
# 沒有額外的縮進(jìn)
if (this_is_one_thing and
that_is_another_thing):
do_something()
# 增加一個(gè)注釋,在能提供語法高亮的編輯器中可以有一些區(qū)分
if (this_is_one_thing and
that_is_another_thing):
# Since both conditions are true, we can frobnicate.
do_something()
# 在條件判斷的語句添加額外的縮進(jìn)
if (this_is_one_thing
and that_is_another_thing):
do_something()
- 在多行結(jié)構(gòu)中的大括號(hào)/中括號(hào)/小括號(hào)的右括號(hào)可以與內(nèi)容對(duì)齊單獨(dú)起一行作為最后一行的第一個(gè)字符,
# 就像這樣:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
# 或者也可以與多行結(jié)構(gòu)的第一行第一個(gè)字符對(duì)齊,就像這樣:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
2. 制表符還是空格?
空格是首選的縮進(jìn)方式。
制表符只能用于與同樣使用制表符縮進(jìn)的代碼保持一致。
Python3不允許同時(shí)使用空格和制表符的縮進(jìn)。
3. 行的最大長(zhǎng)度
- 所有行限制的最大字符數(shù)為79。
- 沒有結(jié)構(gòu)化限制的大塊文本(文檔字符或者注釋),每行的最大字符數(shù)限制在72。
4. 在二元運(yùn)算符之前應(yīng)該換行嗎?
幾十年來,推薦的風(fēng)格是在二元運(yùn)算符之后中斷。但是這回影響可讀性,原因有二:操作符一般分布在屏幕上不同的列中,而且每個(gè)運(yùn)算符被移到了操作數(shù)的上一行。
下面例子這個(gè)情況就需要額外注意,那些變量是相加的,那些變量是相減的:
# 不推薦: 操作符離操作數(shù)太遠(yuǎn)
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
為了解決這種可讀性的問題,數(shù)學(xué)家和他們的出版商遵循了相反的約定。
遵循數(shù)學(xué)的傳統(tǒng)能產(chǎn)出更多可讀性高的代碼:
# 推薦:運(yùn)算符和操作數(shù)很容易進(jìn)行匹配
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
5. 空行
- 頂層函數(shù)和類的定義,前后用兩個(gè)空行隔開。
- 類里的方法定義用一個(gè)空行隔開。
- 相關(guān)的功能組可以用額外的空行(謹(jǐn)慎使用)隔開。
- 一堆相關(guān)的單行代碼之間的空白行可以省略。
- 在函數(shù)中使用空行來區(qū)分邏輯段(謹(jǐn)慎使用)。
6. 源文件編碼
- Python核心發(fā)布版本中的代碼總是以UTF-8格式編碼(或者在Python2中用ASCII編碼)。
- 使用ASCII(在Python2中)或UTF-8(在Python3中)編碼的文件不應(yīng)具有編碼聲明。
- 對(duì)于Python 3和更高版本,標(biāo)準(zhǔn)庫規(guī)定了以下策略(參見 PEP 3131):
- Python標(biāo)準(zhǔn)庫中的所有標(biāo)識(shí)符必須使用ASCII標(biāo)識(shí)符,并在可行的情況下使用英語單詞(在許多情況下,縮寫和技術(shù)術(shù)語是非英語的)。
- 此外,字符串文字和注釋也必須是ASCII。
7. Imports 導(dǎo)入
-
導(dǎo)入通常在分開的行,例如:
# 推薦: import os import sys # 不推薦: import sys, os # 也可以: from subprocess import Popen, PIPE 導(dǎo)入總是位于文件的頂部,在模塊注釋和文檔字符串之后,在模塊的全局變量與常量之前。
-
導(dǎo)入應(yīng)該按照以下順序分組:
1. 標(biāo)準(zhǔn)庫導(dǎo)入 2. 相關(guān)第三方庫導(dǎo)入 3. 本地應(yīng)用/庫特定導(dǎo)入 4. 你應(yīng)該在每一組導(dǎo)入之間加入空行 -
推薦使用絕對(duì)路徑導(dǎo)入,如果導(dǎo)入系統(tǒng)沒有正確的配置(比如包里的一個(gè)目錄在sys.path里的路徑后),使用絕對(duì)路徑會(huì)更加可讀并且性能更好(至少能提供更好的錯(cuò)誤信息):
import mypkg.sibling from mypkg import sibling from mypkg.sibling import example -
當(dāng)從一個(gè)包含類的模塊中導(dǎo)入類時(shí),常常這么寫:
from myclass import MyClass from foo.bar.yourclass import YourClass -
如果上述的寫法導(dǎo)致名字的沖突,那么這么寫:
import myclass import foo.bar.yourclass然后使用“myclass.MyClass”和“foo.bar.yourclass.YourClass”。
避免通配符的導(dǎo)入(from import *),因?yàn)檫@樣做會(huì)不知道命名空間中存在哪些名字,會(huì)使得讀取接口和許多自動(dòng)化工具之間產(chǎn)生混淆。
8.模塊級(jí)Dunder名稱
模塊級(jí)“dunders”(也就是名字里有兩個(gè)前綴下劃線和兩個(gè)后綴下劃線)
如__all__,__author__,__version__等應(yīng)被放置在模塊文檔字符串之后,以及除from __future__ 之外的import表達(dá)式前面。Python要求將來在模塊中的導(dǎo)入,必須出現(xiàn)在除文檔字符串之外的其他代碼之前。
"""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
4. 字符串引號(hào)
在Python中,單引號(hào)和雙引號(hào)字符串是相同的。PEP不會(huì)為這個(gè)給出建議。選擇一條規(guī)則并堅(jiān)持使用下去。當(dāng)一個(gè)字符串中包含單引號(hào)或者雙引號(hào)字符的時(shí)候,使用和最外層不同的符號(hào)來避免使用反斜杠,從而提高可讀性。
對(duì)于三引號(hào)字符串,總是使用雙引號(hào)字符來與PEP 257中的文檔字符串約定保持一致。
5. 表達(dá)式和語句中的空格
總體原則,避免不必要的空格。
- 各種右括號(hào)前不要加空格。
# 符合約定的代碼
spam(ham[1], {eggs: 2})
# 不符合約定的代碼
spam( ham[ 1 ], { eggs: 2 } )
- 逗號(hào)、冒號(hào)、分號(hào)前不要加空格。
# 符合約定的代碼
if x == 4: print x, y; x, y = y, x
# 不符合約定的代碼
if x == 4 : print x , y ; x , y = y , x
- 函數(shù)的左括號(hào)前不要加空格。如Func(1)。
# 符合約定代碼
spam(1)
# 不符合約定的代碼
spam (1)
- 序列的左括號(hào)前不要加空格。如list[2]。
# 符合約定的代碼
dict['key'] = list[index]
# 不符合約定的代碼
dict ['key'] = list [index]
- 操作符左右各加一個(gè)空格,不要為了對(duì)齊增加空格。
# 符合約定的代碼
x = 1
y = 2
long_variable = 3
# 不符合約定的代碼
x = 1
y = 2
long_variable = 3
- 函數(shù)默認(rèn)參數(shù)使用的賦值符左右省略空格。
# 符合約定的代碼
def complex(real, imag=0.0):
return magic(r=real, i=imag)
# 不符合約定的代碼
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
- 不要將多句語句寫在同一行,盡管使用';'允許。
- if/for/while語句中,即使執(zhí)行語句只有一句,也必須另起一行。
復(fù)合語句(同一行中的多個(gè)語句)通常是不允許的。
# 推薦:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
# 不推薦:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
# 雖然有時(shí)候?qū)⑿〉拇a塊和 if/for/while 放在同一行沒什么問題,多行語句塊的情況不要這樣用,同樣也要避免代碼行太長(zhǎng)!
# 不推薦:
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
# 不推薦:
if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()
try: something()
finally: cleanup()
# 不推薦:
do_one(); do_two(); do_three(long, argument,
list, like, this)
if foo == 'blah': one(); two(); three()
6. Comments 注釋
總體原則,錯(cuò)誤的注釋不如沒有注釋。所以當(dāng)一段代碼發(fā)生變化時(shí),第一件事就是要修改注釋!
注釋必須使用英文,最好是完整的句子,首字母大寫,句后要有結(jié)束符,結(jié)束符后跟兩個(gè)空格,開始下一句。
如果是短語,可以省略結(jié)束符。
- 塊注釋
在一段代碼前增加的注釋。在‘#’后加一空格。段落之間以只有‘#’的行間隔。比如:
# Description : Module config.
#
# Input : None
#
# Output : None
- 行注釋
在一句代碼后加注釋。比如:
x = x + 1 # Increment x
? 但是這種方式盡量少使用。
避免無謂的注釋。
-
文檔字符串
要為所有的公共模塊,函數(shù),類以及方法編寫文檔說明。
非公共的方法沒有必要,但是應(yīng)該有一個(gè)描述方法具體作用的注釋。這個(gè)注釋應(yīng)該在def那一行之后。
對(duì)于單行的文檔說明,尾部的三引號(hào)應(yīng)該和文檔在同一行。
特別需要注意的是,多行文檔說明使用的結(jié)尾三引號(hào)應(yīng)該自成一行,例如:"""Return a foobang Optional plotz says to frobnicate the bizbaz first. """
7. Naming Conventions 命名規(guī)范
總體原則,新編代碼必須按下面命名風(fēng)格進(jìn)行,現(xiàn)有庫的編碼盡量保持風(fēng)格。
Python庫的命名規(guī)范很亂,從來沒能做到完全一致。但是目前有一些推薦的命名標(biāo)準(zhǔn)。
約定俗成的命名約定:
- Names to Avoid 應(yīng)避免的名字
- 永遠(yuǎn)不要使用字母‘l’(小寫的L),‘O’(大寫的O),或者‘I’(大寫的I)作為單字符變量名。
- 在有些字體里,這些字符無法和數(shù)字0和1區(qū)分,如果想用‘l’,用‘L’代替。
- Class Names 類名
- 類名一般使用首字母大寫的約定。
- 在接口被文檔化并且主要被用于調(diào)用的情況下,可以使用函數(shù)的命名風(fēng)格代替。
- 注意,對(duì)于內(nèi)置的變量命名有一個(gè)單獨(dú)的約定:大部分內(nèi)置變量是單個(gè)單詞(或者兩個(gè)單詞連接在一起),首字母大寫的命名法只用于異常名或者內(nèi)部的常量。
- Function Names 函數(shù)名
- 函數(shù)名應(yīng)該小寫,如果想提高可讀性可以用下劃線分隔。
- 大小寫混合僅在為了兼容原來主要以大小寫混合風(fēng)格的情況下使用(比如 threading.py),保持向后兼容性。
- Function and method arguments 函數(shù)和方法參數(shù)
- 始終要將 self 作為實(shí)例方法的的第一個(gè)參數(shù)。
- 始終要將 cls 作為類靜態(tài)方法的第一個(gè)參數(shù)。
- 如果函數(shù)的參數(shù)名和已有的關(guān)鍵詞沖突,在最后加單一下劃線比縮寫或隨意拼寫更好。因此 class_ 比 clss 更好。(也許最好用同義詞來避免這種沖突)
總結(jié):
- 嚴(yán)格要求4個(gè)空格縮進(jìn),而不是制表符
- 注意代碼長(zhǎng)度,每行不超過79個(gè)字符,并適當(dāng)使用換行符
- 注意適當(dāng)?shù)拇a空行以更好的區(qū)分代碼區(qū)域
- 代碼注釋和文檔注釋說明必須正確,并優(yōu)先更新
- 源代碼編碼格式統(tǒng)一使用utf-8,或和舊文件代碼保持一致
- 從文件到類與函數(shù)甚至是變量的命名都要保持規(guī)范,且不要使用中文
- 重要的是要意識(shí)到代碼的閱讀比編寫的頻率要高很多很多
以上就是PEP8規(guī)范的解讀內(nèi)容,怎么樣?是不是有點(diǎn)頭大?別著急,下篇文章我們將分享一下Google的代碼規(guī)范,讓大家對(duì)于大公司的編碼規(guī)范有一個(gè)更好的了解。
如果喜歡或者對(duì)你有幫助的小伙伴,歡迎大家關(guān)注我的公眾號(hào):后廠程序員,并分享、點(diǎn)贊、在看 三連