python編碼規(guī)范

python編寫規(guī)范

一、說(shuō)明
二、內(nèi)容
1. 代碼布局
1.1 縮進(jìn)
1.2 表達(dá)式和語(yǔ)句中的空格
1.3 行的最大長(zhǎng)度
1.4 空行...
1.5 編碼...
2. 語(yǔ)句...
2.1 標(biāo)準(zhǔn)頭部...
2.2 導(dǎo)入(import)...
2.3 賦值...
2.4 分支和循環(huán)...
3. 注釋...
3.1 注釋塊...
3.2 行內(nèi)注釋...
3.3 文檔字符串...
3.4 版本注記...
3.5 模塊注釋...
3.6 函數(shù)和方法注釋...
3.7 類注釋...
4. 命名約定...
4.1 說(shuō)明:命名約定...
4.2 模塊名...
4.4 類名...
4.5 異常名...
4.6 變量、常量、全局變量名...
4.7 函數(shù)名...
4.8 方法名和實(shí)例變量...
4.9 特定的命名方式...
5. 繼承的設(shè)計(jì)...
6. 設(shè)計(jì)建議...

一、 說(shuō)明

為了規(guī)范Python代碼的書寫,提高代碼的可讀性,使編碼人員在代碼上更好的協(xié)作,制定了本規(guī)范。
中標(biāo)軟件有限公司測(cè)試中心員工在編寫Python代碼時(shí),必須遵守本規(guī)范。如對(duì)規(guī)范有異議,請(qǐng)聯(lián)系維護(hù)人員。
編碼規(guī)范的作用:

  • 提高可讀性 ——“任何一個(gè)傻瓜都能寫出計(jì)算機(jī)可以理解的代碼,唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員。”編碼規(guī)范,幫助我們寫出人類容易理解的代碼。
  • 統(tǒng)一全局,促進(jìn)****團(tuán)隊(duì)協(xié)作—— 開發(fā)是一個(gè)團(tuán)隊(duì)活動(dòng),而不是個(gè)人的英雄主義。
  • 有助于知識(shí)傳遞,加快工作交接 ——風(fēng)格的相似性,能讓編碼人員更迅速,更容易理解一些陌生的代碼,更快速地理解別人的代碼。
  • 減少名字增生,降低維護(hù)成本 ——在沒有規(guī)范的情況下,很容易為同一類型的實(shí)例起不同的名字。
  • 強(qiáng)調(diào)變量之間的關(guān)系,降低缺陷引入的機(jī)會(huì) ——命名可以表示一定的邏輯關(guān)系,使開發(fā)人員在使用時(shí)保持警惕,從而一定程度上減少缺陷被引入的機(jī)會(huì)。
  • 提高個(gè)人能力

二、 內(nèi)容

1. 代碼布局

1.1 縮進(jìn)

推薦以4個(gè)空格作為一個(gè)縮進(jìn)層次。

1.2 表達(dá)式和語(yǔ)句中的空格

1. 前導(dǎo)空格(縮進(jìn))
最流行的Python縮進(jìn)方式是僅使用空格,其次是僅使用制表符。對(duì)于新的項(xiàng)目,應(yīng)該僅使用空格而不是制表符。
2. 非前導(dǎo)空格
非前導(dǎo)空格在Python代碼中沒有意義,但適當(dāng)?shù)丶尤敕乔皩?dǎo)空格可以增進(jìn)代碼可讀性:
(1)在二元算術(shù)、邏輯運(yùn)算符前后加空格,如:

**示例:**
a = b + c
if a and b:
    pass

(2)在一元前綴運(yùn)算符后不加空格,如:

**示例:**
if !flg:
pass

(3)“:”用在行尾時(shí)前后皆不加空格,如分支、循環(huán)、函數(shù)和類定義語(yǔ)言;用在非行尾時(shí)后端加空格,如dict對(duì)象的定義:

**示例:**
d = {*'key'*: *'value'*}

(4)括號(hào)(含圓括號(hào)、方括號(hào)和花括號(hào))前后不加空格,如:

**示例:**
do_something(arg1, arg2)

(5)逗號(hào)后面加一個(gè)空格,前面不加空格。

1.3 行的最大長(zhǎng)度

每行的最大長(zhǎng)度不得超過80個(gè)字符的標(biāo)準(zhǔn)。超過80個(gè)字符的,建議使用以下方式將單個(gè)長(zhǎng)行折疊成多個(gè)短行:
(1)為長(zhǎng)變量名換一個(gè)短名,如:

**錯(cuò)誤寫法:**
this.is.a.very.long.variable_name = this.is.another.long.variable_name
**正確寫法:**
variable_name1 = this.is.a.very.long.variable_name
variable_name2 = this.is.another.variable_name
variable_name1 = variable_name2

(2)在括號(hào)(包括圓括號(hào)、方括號(hào)和花括號(hào))內(nèi)的分隔符后換行,如:

**示例:**
class **Edit**(Base):
    def **__init__**(*self*, parent, width,
    font = FONT, color = BLACK, pos = POS, style = 0):  # 注意:此行與上一行保持同樣縮進(jìn)
        pass

(3)在長(zhǎng)行加入續(xù)行符強(qiáng)行斷行,斷行的位置應(yīng)在操作符前,如:

**示例:**
if color == WHITE or color == BLACK \
or color == BLUE:  # 注意:換行與首行保持同樣的縮進(jìn)(或均不縮進(jìn))
    do_something(color)

1.4 空行

輸入空行時(shí),一般遵循以下原則:
(1)在import不同種類的模塊間加空行;
(2)頂層函數(shù)和類的定義之間加空行;
(3)在類與類的定義之間加空行;
(4)在函數(shù)與函數(shù)的定義之間加空行;
(5)在class定義行和其第一個(gè)方法定義之間加空行;
(6)在函數(shù)中的邏輯段落間加空行,即把相關(guān)的代碼緊湊寫在一起,作為一個(gè)邏輯段落,段落間以空行分隔。

1.5 編碼

所有的Python腳本文件都應(yīng)在文件頭標(biāo)上#-- coding:utf8 -- ;用于設(shè)置編輯器,默認(rèn)保存為utf8格式:

#-*- coding:utf8 -*-

2. 語(yǔ)句

2.1 標(biāo)準(zhǔn)頭部

一般情況下使用如下標(biāo)準(zhǔn)頭部語(yǔ)句:

#!/usr/bin/python

如果需要使用自定義的Python編譯環(huán)境,可使用類似如下的頭部語(yǔ)句:

#!/usr/bin/env python2.7

說(shuō)明:該行語(yǔ)句的作用是幫助內(nèi)核找到Python解釋器,但通常在Python導(dǎo)入模塊時(shí)被忽略;只有直接執(zhí)行單個(gè)文件時(shí),該語(yǔ)句才是必要的。

2.2 導(dǎo)入(import)

1. 通常應(yīng)該在單獨(dú)的行中導(dǎo)入(import),例如“正確寫法1”;若需要在一行中從一個(gè)模塊導(dǎo)入多個(gè)類,可參照“正確寫法2”:

**錯(cuò)誤寫法:**
import sys, os
**正確寫法****1****:**
import sys
import os
**正確寫法****2****:**
from types import StringType, ListType

2. 導(dǎo)入語(yǔ)句的位置及導(dǎo)入順序
通常將import語(yǔ)句放置在文件的頂部,僅在模塊注釋和文檔字符串之后,在模塊的全局變量和常量之前。導(dǎo)入語(yǔ)句應(yīng)該有順序地成組安放:
(1)首先,導(dǎo)入標(biāo)準(zhǔn)庫(kù)(內(nèi)置模塊);
(2)其次,導(dǎo)入第三方模塊(引用的第三方包);
(3)最后,導(dǎo)入自己開發(fā)的項(xiàng)目中的其他模塊;
在每組導(dǎo)入之間放置一個(gè)空行。
3. 導(dǎo)入類的方法
從一個(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方式即可。

2.3 賦值

對(duì)于賦值語(yǔ)言,主要是不要做無(wú)謂的對(duì)齊,如:

**錯(cuò)誤寫法:**
a        = 1
var      = 2
fn       = callback_function
**正確寫法:**
a = 1
var = 2
fn = callback_function

2.4 分支和循環(huán)

各種分支和循環(huán)語(yǔ)句不要寫成一行,如:

**錯(cuò)誤寫法:**
if !flg: pass
for i in xrange(10): print i
**正確寫法:**
if !flg:
    pass
for i in xrange(10):
    print i

3. 注釋

代碼修改時(shí),始終優(yōu)先更新注釋。注釋應(yīng)該是完整的句子,如果注釋是一個(gè)短語(yǔ)或句子,首字母應(yīng)該大寫,除非他是一個(gè)以小寫字母開頭的標(biāo)識(shí)符(如果以中文注釋可忽略此要求)。

3.1 注釋塊

注釋塊通常用于跟隨著一些代碼并和這些代碼有著相同的縮進(jìn)層次。注釋塊中每行均以“#”和一個(gè)空格開始。注釋塊內(nèi)的段落間以僅含單個(gè)“#”的行分割。注釋塊上下方最好各有一空行。

3.2 行內(nèi)注釋

行內(nèi)注釋是和語(yǔ)句在同一行的注釋。行內(nèi)注釋應(yīng)該至少用兩個(gè)空格和語(yǔ)句分開,且應(yīng)該以“#”和單個(gè)空格開始,如:

**示例:**
x = x + 1  # Increment x

如果語(yǔ)意很明了,那么行內(nèi)注釋則不必要。

3.3 文檔字符串

為所有公共模塊、函數(shù)、類和方法編寫文檔字符串。文檔字符串對(duì)非公開的方法不是必要的,但應(yīng)該有一個(gè)注釋描述這個(gè)方法的作用。這個(gè)注釋應(yīng)該在“def”行之后。
一定注意,多行文檔字符串結(jié)尾的"""應(yīng)該單獨(dú)成行,例如:

**示例:**
*"""Return a foobang*
*Optional plotz says to frobnicate the bizbaz first*
*"""*

對(duì)單行的文檔字符串,結(jié)尾的"""在同一行也可以,例如:

*"""Return a foobang"""*

3.4 版本注記

版本注記可以參照如下示例代碼:

**示例:**
__version__ = *"$Revision: 1.4 $"*

這行應(yīng)該包含在模塊的文檔字符串之后,所有代碼之前,上下用一個(gè)空行分割。

3.5 模塊注釋

每個(gè)模塊注釋都應(yīng)該包含下列項(xiàng),依次是:
(1)版權(quán)聲明;
(2)模塊注釋內(nèi)容,包括模塊描述、模塊中的類和方法的描述、版本及維護(hù)信息等;
(3)作者聲明,標(biāo)識(shí)文件的原作者;

**示例:**
# Copyright (C), 2010-2013, China Standard Software Co., Ltd.
*"""*
*FileName: Test.py*
*Author: fei.liu*
*Version: 0.1*
*Date: 2013-02-27*
*Description: **用一行文字概述模塊或腳本,用句號(hào)結(jié)尾。*
*    ClassFoo: **一行概述該模塊中的類的用途。*
*    functionBar(): **一行概述該模塊中的函數(shù)的用途。*
*History: /* **歷史修改記錄** */*
*<Author>   <Date>   <Version>   <Desc>*
*fei.liu  2013-03-04   1.0      Release*
*"""*
__authors__ = [
  *'"John Smith" <johnsmith@example.com>'*,
  *'"Joe Paranoid" <joeisgone@example.com>'*,
]

3.6 函數(shù)和方法注釋

任何函數(shù)或方法都需要一個(gè)文檔字符串,對(duì)于任何外部可訪問的函數(shù)或方法,文檔字符串尤為重要。
文檔字符串應(yīng)該包含函數(shù)的作用,以及參數(shù)、輸入和輸出的詳細(xì)描述:
(1)Args:輸入?yún)?shù)的具體描述;如果參數(shù)要求特定的數(shù)據(jù)類型或者設(shè)置了參數(shù)的默認(rèn)值,那么應(yīng)該在文檔字符串中明確說(shuō)明;
(2)Returns:輸出(返回)數(shù)據(jù)的具體描述;
(3)Raises:應(yīng)該列出該函數(shù)可能觸發(fā)的所有異常;

**示例:**
def **fetch_bigtable_rows**(big_table, keys, other_silly_variable=None):
*"""**取出表格中的多行內(nèi)容*
*    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 rowto 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

3.7 類注釋

類定義下方必須有一個(gè)用于描述該類的文檔字符串(docString)。如果類中有公共屬性(Attributes),那么文檔字符串中應(yīng)該說(shuō)明這些公共屬性的意義。

**示例:**
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."""*

4. 命名約定

4.1 說(shuō)明:命名約定

禁止使用字符“l(fā)”、“O”或“I”作為單字符的變量名。在某些字體中無(wú)法將這些字符與數(shù)字1和0區(qū)分開。

4.2 模塊名

模塊名應(yīng)該是不含下劃線的、簡(jiǎn)短的、全小寫的名字;對(duì)于默認(rèn)僅在包(Packages)內(nèi)使用的模塊,可以加一個(gè)下劃線前綴,如:

**示例:**
module.py
_internal_module.py

4.4 類名

類名使用CapWords約定(單詞首字母大寫,不使用下劃線連接單詞,也不加入C、T等前綴);內(nèi)部使用的類需要在名稱前加一個(gè)前導(dǎo)下劃線,如:

**示例:**
class **ThisIsAClass**(object):
pass
class _**ThisIsAClass**(object):
pass

4.5 異常名

異常名使用CapWords命名規(guī)則(單詞首字母大寫,不使用下劃線連接單詞)。

4.6 變量、常量、全局變量名

Python一般通過“from M import *”來(lái)從模塊中導(dǎo)入相關(guān)內(nèi)容(變量、類、函數(shù)等),必須用一個(gè)下劃線作全局變量(內(nèi)部函數(shù)或類)的前綴防止其被導(dǎo)出(exporting)。
1. 常量
常量名的所有字母均大寫,由下劃線連接各個(gè)單詞,如:

**示例:**
WHITE = 0XFFFFFF
THIS_IS_A_CONSTANT = 1

2. 變量
(1)變量名全部小寫,由下劃線連接各個(gè)單詞,如:

**示例:**
color = WHITE
this_is_a_variable = 1

(2)不論是類成員變量還是全局變量,均不使用m或g前綴。私有類成員使用單一下劃線前綴標(biāo)識(shí);
(3)變量名不應(yīng)帶有類型信息,因?yàn)镻ython是動(dòng)態(tài)類型語(yǔ)言;如iValue、names_list、dict_obj等都是不好的命名。
3. 全局變量
必須用一個(gè)下劃線作為全局變量的前綴防止其被導(dǎo)出。

4.7 函數(shù)名

函數(shù)名應(yīng)該為小寫,可用下劃線風(fēng)格單詞以增加可讀性。

4.8 方法名和實(shí)例變量

大體上和函數(shù)命名規(guī)則相同:通常使用小寫單詞,必要時(shí)用下劃線分隔增加可讀性。
如果是不打算對(duì)外公開的內(nèi)部方法和實(shí)例,需要在名稱開頭使用一個(gè)前導(dǎo)下劃線。
使用兩個(gè)前導(dǎo)下劃線以表示類私有成員的名字。通常雙前導(dǎo)下劃線僅被用于避免含子類的類中的屬性名沖突。

4.9 特定的命名方式

主要是指xxx形式的系統(tǒng)保留字命名法。項(xiàng)目中也可以使用這種命名,它的意義在于這種形式的變量是只讀的,這種形式的類成員函數(shù)盡量不要重載。如:

**示例:**
class **Base**(object):
    def __**init**__(*self*, id, parent = None):
        *self*.__id__ = id
        *self*.__parent__ = parent
    def __**message**__(*self*, msgid):
        # ...

其中_idparentmessage都采用了系統(tǒng)保留字命名法。

5. 繼承的設(shè)計(jì)

始終要確定一個(gè)類中的方法和實(shí)例變量是否要被公開。通常,永遠(yuǎn)不要將數(shù)據(jù)變量公開,除非你實(shí)現(xiàn)的本質(zhì)上只是記錄,人們總是更喜歡為類提供一個(gè)函數(shù)的接口來(lái)實(shí)現(xiàn)數(shù)據(jù)變量的修改。
同樣,確定你的屬性是否應(yīng)為私有的。私有和非私有的區(qū)別在于:前者永遠(yuǎn)不會(huì)被用在一個(gè)派生類中,而后者可能會(huì)。你應(yīng)該在大腦中就用繼承設(shè)計(jì)好了你的類:(1)私有屬性必須有兩個(gè)前導(dǎo)下劃線,無(wú)后置下劃線;(2)非公有屬性必須有一個(gè)前導(dǎo)下劃線,無(wú)后置下劃線;(3)公共屬性沒有前導(dǎo)和后置下劃線,除非它們與保留字沖突,在此情況下,單個(gè)后置下劃線比前置或混亂的拼寫要好,例如:class_優(yōu)于klass。

6. 設(shè)計(jì)建議

單個(gè)元素(singletons)的比較,如None應(yīng)該使用“is”或“is not”。當(dāng)你本意是“if x is not None”時(shí),對(duì)寫成“if x”要小心。例如當(dāng)你測(cè)試一個(gè)默認(rèn)為None的變量或參數(shù)是否被設(shè)置為其它值時(shí),這個(gè)其它值也許在布爾上下文(Boolean context)中是False。
基于類的異常總是好過基于字符串的異常。模塊和包應(yīng)該定義它們自己的域內(nèi)特定的基異常類,基類應(yīng)該是內(nèi)建的Exception類的子類,還始終包含一個(gè)類的文檔字符串。例如:

**示例:**
#!/usr/bin/Python
class(Exception):
*"""Base class for errors in the email package."""*
MessageError

使用字符串方法(methods)代替字符串模塊,除非必須向后兼容Python 2.0以前的版本。字符串方法總是非常快,而且和unicode字符串共用同樣的API(應(yīng)用程序接口),在檢查前綴或后綴時(shí)避免對(duì)字符串進(jìn)行切片。用startswith()和endswith()代替,因?yàn)檫@樣出現(xiàn)錯(cuò)誤的機(jī)率更小。例如:

**錯(cuò)誤寫法:**
if foo[:3] == *'bar'*:
**正確寫法:**
if foo.startswith(*'bar'*):

特殊情況下,如果你的代碼必須工作在Python 1.5.2,對(duì)象類型的比較應(yīng)該始終用isinstance()代替直接比較類型,例如:

**錯(cuò)誤寫法:**
if type(obj) is type(1):
**正確寫法:**
if isinstance(obj, int):

檢查一個(gè)對(duì)象是否是字符串時(shí),謹(jǐn)記它也可能是unicode字符串!在Python 2.3中,str和unicode有公共的基類basestring,所以你可以這樣做:

if isinstance(obj, basestring):

在Python 2.2類型模塊為此定義了StringTypes類型,例如:

#!/usr/bin/Python
from types import StringTypes
if isinstance(obj, StringTypes):

對(duì)序列(字符串、列表、元組)而言,使用空列表是false這個(gè)事實(shí),因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。書寫字符串文字時(shí)不要依賴于有意義的后置空格。這種后置空格在視覺上是不可辨別的,并且有些編輯器會(huì)將它們修整掉。不要用“==”來(lái)比較布爾型的值以確定是True或False(布爾型是Python2.3中新增的):

**錯(cuò)誤寫法:**
if greeting == True:
**正確寫法:**
if greeting:
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容