Python編碼規(guī)范匯編_第1頁
Python編碼規(guī)范匯編_第2頁
Python編碼規(guī)范匯編_第3頁
Python編碼規(guī)范匯編_第4頁
Python編碼規(guī)范匯編_第5頁
已閱讀5頁,還剩46頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Python編碼規(guī)范匯編前言:為了讓不同編碼習(xí)慣的開發(fā)者更好的協(xié)作配合,并且形成良好的基礎(chǔ)編碼規(guī)范與風(fēng)格,我們以PEP8為基礎(chǔ),修改了陳舊的規(guī)則,豐富了示例,并整理了工作中常見的不規(guī)范操作,最終形成此Python編碼規(guī)范與風(fēng)格。一、編碼風(fēng)格1.1縮進(jìn)1.2每行最大長度1.3空白符1.4操作符1.5括號1.6空行1.7源文件編碼1.8Shebang1.9模塊引用(import)1.10模塊中的魔術(shù)變量(dunders)1.11注釋1.12文檔字符串1.13類型提示1.14字符串1.15文件和sockets1.16訪問控制1.17Main1.18命名二、編碼規(guī)范2.1三目運(yùn)算符2.2None條件的判斷2.3lambda匿名函數(shù)2.4異常2.5條件表達(dá)式2.6True/False布爾運(yùn)算2.7列表推導(dǎo)式2.8函數(shù)2.9變量工具與配置flake8pylintblackEditorConfig注意事項(xiàng)本規(guī)范適用于所有使用Python語言作為開發(fā)語言的軟件產(chǎn)品。由于Python2在2020年停止維護(hù),建議新增的項(xiàng)目使用Python3.6+,可以使用到更多的高級特性。如果項(xiàng)目有兼容性需求需要支持老版本Python的,那么不涉及的特性可以忽略。本規(guī)范的示例采用符合Python3.6+的語法。必須(Mandatory):用戶必須采用;推薦(Preferable):用戶理應(yīng)采用,但如有特殊情況,可以不采用;可選(Optional):用戶可參考,自行決定是否采用;未明確指明的則默認(rèn)為

必須(Mandatory)。一、編碼風(fēng)格規(guī)范地代碼布局有助于幫助開發(fā)者更容易地理解業(yè)務(wù)邏輯。1.1縮進(jìn)1.1.1

【必須】

對于每級縮進(jìn),統(tǒng)一要求使用4個空格,而非tab鍵。pylint:bad-indentation.1.1.2

【必須】

續(xù)行,要求使用括號等定限界符,并且需要垂直對齊。正確示范#

與定界(括號)符對齊

foo

=

long_function_name(var_one,

var_two,

var_three,

var_four)

#

換行并增加4個額外的空格(一級縮進(jìn))

def

long_function_name(

var_one,

var_two,

var_three,

var_four):

print(var_one)

#

懸掛需要增加一級縮進(jìn)

foo

=

long_function_name(

var_one,

var_two,

var_three,

var_four)錯誤示范

#

當(dāng)不使用垂直對齊時,第一行不允許加參數(shù)

foo

=

long_function_name(var_one,

var_two,

var_three,

var_four)

#

下面這種情況,需要增加額外的縮進(jìn),否則無法區(qū)分代碼所在的縮進(jìn)級別

def

long_function_name(

var_one,

var_two,

var_three,

var_four):

print(var_one)1.1.3

【推薦】

如果包含定界符(括號,中括號,大括號)的表達(dá)式跨越多行,那么定界符的擴(kuò)回符,可以放置與最后一行的非空字符對齊或者與構(gòu)造多行的開始第一個字符對齊。正確示范#

與最后一行的非空字符對齊

my_list

=

[

1,

2,

3,

4,

5,

6,

]

result

=

some_function_that_takes_arguments(

'a',

'b',

'c',

'd',

'e',

'f',

)

#

或者與開始構(gòu)造多行的第一個字符對齊

my_list

=

[

1,

2,

3,

4,

5,

6,

]

result

=

some_function_that_takes_arguments(

'a',

'b',

'c',

'd',

'e',

'f',

)1.1.4

【推薦】

對于會經(jīng)常改動的函數(shù)參數(shù)、列表、字典定義,建議每行一個元素,并且每行增加一個

,

。正確示范yes

=

('y',

'Y',

'yes',

'TRUE',

'True',

'true',

'On',

'on',

'1')

#

基本不再改變

kwlist

=

[

'False',

'None',

'True',

'and',

'as',

'assert',

...

'yield',

#

最后一個元素也增加一個逗號

,方便以后diff不顯示此行

]

person

=

{

'name':

'bob',

'age':

12,

#

可能經(jīng)常增加字段

}錯誤示范#

關(guān)鍵字會不斷增加,每個元素都換行

kwlist

=

['False',

'None',

'True',

'and',

'as',

'assert',

'async',

...

]

person

=

{'name':

'bob',

'age':

12}1.1.5

【可選】

對于if判斷,一般來說盡量不要放置過多的判斷條件。換行時增加4個額外的空格。pycodestyle:E129visuallyindentedlinewithsameindentasnextlogicalline.備注:PEP8沒有明確規(guī)定,以下幾種都是允許的。建議使用前面2種方法,后2種會與已有的開源工具沖突。正確示范#

更推薦:在續(xù)行中,增加額外的縮進(jìn)級別。允許and操作符在前

if

(this_is_one_thing

and

that_is_another_thing):

do_something()

#

更推薦:在續(xù)行中,增加額外的縮進(jìn)級別

if

(this_is_one_thing

and

that_is_another_thing):

do_something()

#

允許:與定界符(括號)對齊,不需要額外的縮進(jìn)

if

(this_is_one_thing

and

that_is_another_thing):

do_something()

#

允許:增加注釋,編輯器會提示語法高亮,有助于區(qū)分

if

(this_is_one_thing

and

that_is_another_thing):

#

Since

both

conditions

are

true,

we

can

frobnicate.

do_something()1.2每行最大長度1.2.1

【必須】

每行最多不超過

120

個字符。每行代碼最大長度限制的根本原因是過長的行會導(dǎo)致閱讀障礙,使得縮進(jìn)失效。pylint:line-too-long.除了以下兩種情況例外:導(dǎo)入模塊語句。注釋中包含的URL。如果需要一個長的字符串,可以用括號實(shí)現(xiàn)隱形連接。正確示范x

=

('This

will

build

a

very

long

long

'

'long

long

long

long

long

long

string')1.3空白符1.3.1

【必須】

在表達(dá)式的賦值符號、操作符左右至少有一個空格。正確示范x

=

y

+

1錯誤示范x=y+1

x

=

y+11.3.2

【必須】

禁止行尾空白。pylint:trailing-whitespace.行尾空白雖然不會造成功能性異常,但是這些空白字符會被源碼管理系統(tǒng)標(biāo)記出來顯示為差異,對開發(fā)人員造成困惱。正確示范#

YES:

尾部沒有空白符號

+

para

=

{}

+

para

=

{}

#

comment錯誤示范#

No:

結(jié)尾存在多余空白符號

-

para

=

{}?????

-

para

=

{}

#

comment??????1.4操作符1.4.1

【推薦】

Python沒有三目操作符,對于二目操作符來說,操作符允許在換行符之后出現(xiàn)。備注:pycodestyle工具與此條目相反,PEP8推薦操作符在這之前,更具備可讀性。PEP8:ShouldaLineBreakBeforeorAfteraBinaryOperator?。屏蔽pycodestyle:W503linebreakbeforebinaryoperator正確示范#

YES:

易于將運(yùn)算符與操作數(shù)匹配,可讀性高

income

=

(gross_wages

+

taxable_interest

+

(dividends

-

qualified_dividends)

-

ira_deduction

-

student_loan_interest)錯誤示范#

No:

運(yùn)算符的位置遠(yuǎn)離其操作數(shù)

income

=

(gross_wages

+

taxable_interest

+

(dividends

-

qualified_dividends)

-

ira_deduction

-

student_loan_interest)1.5括號1.5.1

【必須】

tuple元組不允許逗號結(jié)尾,顯式增加括號規(guī)避。即使一個元素也加上括號。pylint:trailing-comma-tuple.行尾的逗號可能導(dǎo)致本來要定義一個簡單變量,結(jié)果變成tuple變量。正確示范trailingcomma

=

(['f'],)

return

(1,)錯誤示范trailingcomma

=

['f'],

#

tuple

return

1,1.6空行1.6.1

【必須】

模塊中的一級函數(shù)和類定義之間,需要空兩行。pycodestyle:E302expected2blanklines.1.6.2

【必須】

類中函數(shù)定義之間,空一行。pycodestyle:E302expected1blankline.1.6.3

【必須】

源文件須使用且僅使用

一個換行符

作為結(jié)尾。pylint:missing-final-newline,

trailing-newlines.1.6.4

【必須】

通常每個語句應(yīng)該獨(dú)占一行。pylint:multiple-statements.如果測試結(jié)果與測試語句在一行放得下,你也可以將它們放在同一行。如果是

if

語句,只有在沒有

else

時才能這樣做。特別地,絕不要對

try/except

這樣做,因?yàn)?/p>

try

except

不能放在同一行。正確示范if

foo:

bar(foo)

else:

baz(foo)

try:

bar(foo)

except

ValueError:

baz(foo)錯誤示范if

foo:

bar(foo)

else:

baz(foo)

try:

bar(foo)

except

ValueError:

baz(foo)

try:

bar(foo)

except

ValueError:

baz(foo)1.6.5

【推薦】

可以在代碼段中的空一行來區(qū)分不同業(yè)務(wù)邏輯塊。"""This

is

the

example

module.

This

module

does

stuff.

"""

import

os

def

foo():

pass

class

MyClass():

def

__init__(self):

pass

def

foo(self):

pass

class

AnotherClass(object):

"""Another

class.

This

is

some

comments

for

another

class

"""

def

__init__(self,

a,

b):

if

a

>

b:

self._min

=

b

self._max

=

a

else:

self._min

=

a

self._max

=

b

self._gap

=

self._max

=

self._min

def

foo(self):

pass1.7源文件編碼1.7.1

【必須】

源文件編碼需統(tǒng)一使用

UTF-8

編碼,以下內(nèi)容需要增加到每一個python文件的頭部。#

-*-

coding:

utf-8

-*-1.7.2

【必須】

**避免不同操作系統(tǒng)對文件換行處理的方式不同,一律使用

LF**。pylint:mixed-line-endings,

unexpected-line-ending-format.1.8Shebang1.8.1

【必須】

程序的main文件應(yīng)該以

#!/usr/bin/envpython2

或者

#!/usr/bin/envpython3

開始,可以同時支持Python2、Python3的#!/usr/bin/envpython。非程序入口的文件不應(yīng)該出現(xiàn)Shebang。正確示范#!/usr/bin/env

python3

#

-*-

coding:

utf-8

-*-

#1.9模塊引用(import)1.9.1

【必須】

每個導(dǎo)入應(yīng)該獨(dú)占一行。pylint:multiple-imports.正確示范import

os

import

sys錯誤示范import

os,

sys1.9.2

【必須】

導(dǎo)入總應(yīng)該放在文件頂部,位于模塊注釋和文檔字符串之后,模塊全局變量和常量之前。pylint:wrong-import-order.導(dǎo)入應(yīng)該按照從最通用到最不通用的順序分組,每個分組之間,需要空一行:標(biāo)準(zhǔn)庫導(dǎo)入第三方庫導(dǎo)入本地導(dǎo)入每種分組中,建議每個模塊的完整包路徑按

字典序

排序,并忽略大小寫。正確示范import

foo

from

foo

import

bar

from

foo.bar

import

baz

from

foo.bar

import

Quux

from

Foob

import

ar1.9.3

【必須】

避免使用

from<module>import*,因?yàn)榭赡軙斐擅臻g的污染。pylint:wildcard-import.1.9.4

【必須】

禁止導(dǎo)入了模塊卻不使用它。pylint:unused-import.正確示范import

os

#

used

dir_path

=

os.path.abspath('.')錯誤示范import

os

#

unused

!

#

dir_path

=

os.path.abspath('.')1.10模塊中的魔術(shù)變量(dunders)1.10.1

【必須】

對于兩個

_

開頭和兩個

_

結(jié)尾的變量,如

__all__,__author__,__version__等,應(yīng)該放在模塊文檔之后,其他模塊導(dǎo)入之前(__future__

除外)。1.10.2

【必須】

Python要求

future

導(dǎo)入必須出現(xiàn)在其他模塊導(dǎo)入之前。pylint:misplaced-future.正確示范#

-*-

coding:

utf-8

-*-

#

#

Copyright

@

2020

T

"""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

sys1.11注釋有效的注釋有助于幫助開發(fā)者更快地理解代碼,模塊,函數(shù),方法,以及行內(nèi)注釋的都有各自的風(fēng)格。1.11.1

【必須】

所有#開頭的注釋,必須與所在的代碼塊同級,并置放在代碼之上。pycodestyle:E262inlinecommentshouldstartwith'#'.1.11.2

【必須】

注釋的每一行都應(yīng)該以#和一個空格開頭。pycodestyle:E266toomanyleading'#'forblockcomment,

E262inlinecommentshouldstartwith'#'.1.11.3

【必須】

行內(nèi)注釋#與代碼離開至少2個空格。pycodestyle:E261atleasttwospacesbeforeinlinecomment.1.11.4

【必須】

塊注釋:對于復(fù)雜的操作,可以在代碼之前寫若干行注釋,對簡單的代碼,可以放在行內(nèi)。與代碼離開至少2個空格。正確示范#

this

is

a

very

complex

operation,

please

#

read

this

carefully

if

i

&

(i-1)

==

0:

#

do

my

job

...

#

單行注釋,為可讀性,至少離開代碼2個空格

x

=

x

+

1

#

Compensate

for

border1.11.5

【必須】

TODO注釋需要加上名字。TODO注釋應(yīng)該在所有開頭處包含

TODO

字符串,緊跟著是用括號括起來的你的名字,email地址或其它標(biāo)識符,然后是一個可選的冒號。接著必須有一行注釋,解釋要做什么。主要目的是為了有一個統(tǒng)一的TODO格式,這樣添加注釋的人就可以搜索到(并可以按需提供更多細(xì)節(jié))。寫了TODO注釋并不保證寫的人會親自解決問題。當(dāng)你寫了一個TODO,請注上你的名字。為臨時代碼使用TODO注釋,它是一種短期解決方案。常見的IDE在提交代碼時,會檢查變更中包含了TODO并提醒開發(fā)者,防止提交是忘記還有未完成的代碼。如果TODO是將來做某事的形式,那么請確保包含一個指定的日期或者一個特定的事件(條件)。相同地,也可以留下

FIXME,

NOTES

注釋。正確示范#

TODO(zhangsan):

Change

this

to

use

relations.

#

FIXME(zhangsan@):

Please

fix

me

here.

#

NOTES(zhangsan):

This

is

some

notes.1.12文檔字符串Docstring文檔字符串提供了將文檔與Python模塊,函數(shù),類和方法相關(guān)聯(lián)的便捷方法。def

foobar():

"""Return

a

foobang

Optional

plotz

says

to

frobnicate

the

bizbaz

first.

"""PEP257全面描述了文檔字符串的風(fēng)格。1.12.1

【推薦】

需對外發(fā)布的public模塊,函數(shù),類,方法等需要包含文檔字符串。內(nèi)部使用的方法,函數(shù)等,要求使用簡單的注釋描述功能。pylint:missing-module-docstring,

missing-class-docstring,

missing-function-docstring.一個函數(shù)或方法,如果可以直接被其他開發(fā)者使用,需要提供文檔明確其含義,需要指出輸入,輸出,以及異常內(nèi)容。1.12.2

【必須】

第一行應(yīng)為文檔名,空一行后,輸入文檔描述。1.12.3

【推薦】

在使用文檔字符串時,推薦使用

reStructuredText

風(fēng)格類型。正確示范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.

:param

big_table:

An

open

Bigtable

Table

instance.

:param

keys:

A

sequence

of

strings

representing

the

key

of

each

table

row

to

fetch.

:param

other_silly_variable:

Another

optional

variable,

that

has

a

much

longer

name

than

the

other

args,

and

which

does

nothing.

:return:

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

ValueError:

if

`keys`

is

empty.

:raises

IOError:

An

error

occurred

accessing

the

bigtable.Table

object.

"""

pass1.12.4

【推薦】

類應(yīng)該在其定義下有一個用于描述該類的文檔字符串。如果類有公共屬性(Attributes),那么文檔中應(yīng)該有一個屬性(Attributes)段,并且應(yīng)該遵守和函數(shù)參數(shù)相同的格式。正確示范class

SampleClass(object):

"""Summary

of

class

here.

Longer

class

information

Longer

class

information

:ivar

likes_spam:

A

boolean

indicating

if

we

like

SPAM

or

not.

:ivar

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."""1.13類型提示Python是動態(tài)語言,在運(yùn)行時無需指定變量類型。雖然運(yùn)行時不會執(zhí)行函數(shù)與變量類型注解,但類型提示有助于閱讀代碼、重構(gòu)、靜態(tài)代碼檢查與IDE的語法提示。推薦在項(xiàng)目中使用該特性。更多使用可以參考類型標(biāo)注支持。類型提示示例代碼from

typing

import

List

class

Container(object):

def

__init__(self)

->

None:

self.elements:

List[int]

=

[]

def

append(self,

element:

int)

->

None:

self.elements.append(element)

def

greeting(name:

str)

->

str:

return

'Hello

'

+

name

#

變量定義

lang:

str

=

'zh'

success_code:

int

=

01.13.1

【必須】

模塊級變量,類和實(shí)例變量以及局部變量的注釋應(yīng)在冒號后面有一個空格。pycodestyle:E231missingwhitespaceafter':'.1.13.2

【必須】

冒號前不應(yīng)有空格。1.13.3

【必須】

如果有賦值符,則等號在兩邊應(yīng)恰好有一個空格。pycodestyle:E225missingwhitespacearoundoperator.正確示范code:

int

=

10

class

Point(object):

coords:

Tuple[int,

int]

=

(0,

0)

label:

str

=

'<unknown>'

def

broadcast(servers:

Sequence[Server],

message:

str

=

'spaces

around

equality

sign')

->

None:

pass錯誤示范code:int

#

No

space

after

colon

code

:

int

#

Space

before

colon

class

Test(object):

result:

int=0

#

No

spaces

around

equality

sign1.13.4

【推薦】

當(dāng)使用類型提示出現(xiàn)循環(huán)引用時,可以在導(dǎo)入的頭部使用

iftyping.TYPE_CHECKING

,且對類型注解使用雙引號或單引號進(jìn)行修飾。正確示范import

typing

if

typing.TYPE_CHECKING:

#

運(yùn)行時不導(dǎo)入

#

For

type

annotation

from

typing

import

Any,

Dict,

List,

Sequence

#

NOQA

from

sphinx.application

import

Sphinx

#

NOQA

class

Parser(docutils.parsers.Parser):

def

set_application(self,

app:

"Sphinx")

->

None:

#

同時采用引號

pass1.14字符串1.14.1

【推薦】

即使參數(shù)都是字符串,也要使用%操作符或者格式化方法格式化字符串。不過也不能一概而論,你需要在+和%之間權(quán)衡。正確示范#

更推薦

x

=

f'name:

{name};

score:

{n}'

#

Python3.6+

以上支持

x

=

'name:

{name};

score:

{n}'.format(name=name,

n=n)

x

=

'name:

{name};

score:

{n}'.format(**{"name":

name,

"n":

n})

x

=

'name:

%(name)s;

score:

%(n)d'

%

{"name":

name,

"n":

n}

#

可接受

x

=

'%s,

%s!'

%

(imperative,

expletive)

x

=

'{},

{}!'.format(imperative,

expletive)

x

=

'name:

%s;

score:

%d'

%

(name,

n)

x

=

'name:

{};

score:

{}'.format(name,

n)錯誤示范x

=

'%s%s'

%

(a,

b)

#

use

+

in

this

case

x

=

'{}{}'.format(a,

b)

#

use

+

in

this

case

x

=

imperative

+

',

'

+

expletive

+

'!'

x

=

'name:

'

+

name

+

';

score:

'

+

str(n)1.14.2

【推薦】

避免在循環(huán)中用

+

+=

操作符來累加字符串。由于字符串是不可變的,這樣做會創(chuàng)建不必要的臨時對象,并且導(dǎo)致二次方而不是線性的運(yùn)行時間。作為替代方案,你可以將每個子串加入列表,然后在循環(huán)結(jié)束后用

.join

連接列表。(也可以將每個子串寫入一個io.StringIO緩存中。)pylint:consider-using-join.正確示范items

=

['<table>']

for

last_name,

first_name

in

employee_list:

items.append('<tr><td>%s,

%s</td></tr>'

%

(last_name,

first_name))

items.append('</table>')

employee_table

=

''.join(items)錯誤示范employee_table

=

'<table>'

for

last_name,

first_name

in

employee_list:

employee_table

+=

'<tr><td>%s,

%s</td></tr>'

%

(last_name,

first_name)

employee_table

+=

'</table>'1.14.3

【推薦】

在同一個文件中,保持使用字符串引號的一致性。使用單引號'

或者雙引號

"

引用字符串,并在同一文件中一直沿用這種風(fēng)格。當(dāng)字符串中包含單引號或者雙引號時,為提高可讀性,使用另外一種引號,代替轉(zhuǎn)義字符。正確示范Python('Why

are

you

hiding

your

eyes?')

Gollum("I'm

scared

of

lint

errors.")

Narrator('"Good!"

thought

a

happy

Python

reviewer.')錯誤示范Python("Why

are

you

hiding

your

eyes?")

Gollum('The

lint.

It

burns.

It

burns

us.')

Gollum("Always

the

great

lint.

Watching.

Watching.")1.14.4

【必須】

如果要引用的字符串為多行時,需要使用雙引號引用字符串。1.14.5

【必須】

文檔字符串(docstring)必須使用三重雙引號

"""。1.14.6

【可選】

避免在代碼中使用三重引號

""",因?yàn)楫?dāng)使用三重引號時,縮進(jìn)方式與其他部分不一致,容易引起誤導(dǎo)。正確示范print("This

is

much

nicer.\n"

"Do

it

this

way.\n")錯誤示范print("""This

is

pretty

ugly.

Don't

do

this.

""")1.14.7

【推薦】

檢查前綴和后綴時,使用

.startswith()

.endswith()

代替字符串切片。正確示范if

foo.startswith('bar'):錯誤示范if

foo[:3]

==

'bar':1.15文件和sockets1.15.1

【必須】

在文件和sockets結(jié)束時,顯式的關(guān)閉它。除文件外,sockets或其他類似文件的對象在沒有必要的情況下打開,會有許多副作用,例如:它們可能會消耗有限的系統(tǒng)資源,如文件描述符。如果這些資源在使用后沒有及時歸還系統(tǒng),那么用于處理這些對象的代碼會將資源消耗殆盡。持有文件將會阻止對于文件的其他諸如移動、刪除之類的操作。僅僅是從邏輯上關(guān)閉文件和sockets,那么它們?nèi)匀豢赡軙黄涔蚕淼某绦蛟跓o意中進(jìn)行讀或者寫操作。只有當(dāng)它們真正被關(guān)閉后,對于它們嘗試進(jìn)行讀或者寫操作將會拋出異常,并使得問題快速顯現(xiàn)出來。而且,幻想當(dāng)文件對象析構(gòu)時,文件和sockets會自動關(guān)閉,試圖將文件對象的生命周期和文件的狀態(tài)綁定在一起的想法,都是不現(xiàn)實(shí)的。因?yàn)橛腥缦略颍簺]有任何方法可以確保運(yùn)行環(huán)境會真正的執(zhí)行文件的析構(gòu)。不同的Python實(shí)現(xiàn)采用不同的內(nèi)存管理技術(shù),比如延時垃圾處理機(jī)制。延時垃圾處理機(jī)制可能會導(dǎo)致對象生命周期被任意無限制的延長。對于文件意外的引用,會導(dǎo)致對于文件的持有時間超出預(yù)期(比如對于異常的跟蹤,包含有全局變量等)。1.15.2

【推薦】

推薦使用

with

語句管理文件。with

open("hello.txt")

as

hello_file:

for

line

in

hello_file:

print(line)對于不支持使用

with

語句的類似文件的對象,使用

contextlib.closing():import

contextlib

with

contextlib.closing(urllib.urlopen("/"))

as

front_page:

for

line

in

front_page:

print(line)LegacyAppEngine中Python2.5的代碼如使用

with

語句,需要添加

from__future__importwith_statement.1.16訪問控制在Python中,對于瑣碎又不太重要的訪問函數(shù),應(yīng)該直接使用公有變量來取代它們,這樣可以避免額外的函數(shù)調(diào)用開銷。當(dāng)添加更多功能時,也可以用屬性(property)來保持語法的一致性。1.16.1

【推薦】

如果訪問屬性后需要復(fù)雜的邏輯處理,或者變量的訪問開銷很顯著,那么應(yīng)該使用像

get_foo()

set_foo()

這樣的函數(shù)調(diào)用。如果之前的代碼行為已經(jīng)通過屬性(property)訪問,那么就不要將新的訪問函數(shù)與屬性綁定。否則,任何試圖通過老方法訪問變量的代碼就沒法運(yùn)行,使用者也就會意識到復(fù)雜性發(fā)生了變化。(如果可以重構(gòu)這個代碼是最好的了)1.17Main即使是一個打算被用作腳本的文件,也應(yīng)該是可導(dǎo)入的。并且簡單的導(dǎo)入不應(yīng)該導(dǎo)致這個腳本的主功能(mainfunctionality)被執(zhí)行,這是一種副作用。主功能應(yīng)該放在一個main()函數(shù)中。1.17.1

【必須】

所有的文件都應(yīng)該可以被導(dǎo)入。對不需要作為程序入口地方添加

if__name__=='__main__'

。在Python中,pydoc以及單元測試要求模塊必須是可導(dǎo)入的。你的代碼應(yīng)該在執(zhí)行主程序前總是檢查

if__name__=='__main__'

,這樣當(dāng)模塊被導(dǎo)入時主程序就不會被執(zhí)行。所有的頂級代碼在模塊導(dǎo)入時都會被執(zhí)行。要小心不要去調(diào)用函數(shù),創(chuàng)建對象,或者執(zhí)行那些不應(yīng)該在使用pydoc時執(zhí)行的操作。正確示范def

main():

...

if

__name__

==

'__main__':

main()1.18命名module_name,package_name,ClassName,method_name,ExceptionName,function_name,GLOBAL_VAR_NAME,instance_var_name,function_parameter_name,local_var_name.應(yīng)該避免的名稱:單字符名稱,除了計數(shù)器和迭代器。包/模塊名中的連字符(-)。雙下劃線開頭并結(jié)尾的名稱(Python保留,例如__init__)。1.18.1

【推薦】

命名約定規(guī)則如下:pylint:invalid-name.所謂內(nèi)部(Internal)

表示僅模塊內(nèi)可用,或者,在類內(nèi)是保護(hù)或私有的。用單下劃線

(_)

開頭表示模塊變量或函數(shù)是protected的(使用frommoduleimport*時不會包含)。用雙下劃線

(__)

開頭的實(shí)例變量或方法表示類內(nèi)私有。將相關(guān)的類和頂級函數(shù)放在同一個模塊里。不像Java,沒必要限制一個類一個模塊。對類名使用大寫字母開頭的單詞(如CapWords,即Pascal風(fēng)格),但是模塊名應(yīng)該用小寫加下劃線的方式(如lower_with_under.py)。盡管已經(jīng)有很多現(xiàn)存的模塊使用類似于CapWords.py這樣的命名,但現(xiàn)在已經(jīng)不鼓勵這樣做,因?yàn)槿绻K名碰巧和類名一致,這會讓人困擾。Python之父Guido推薦的規(guī)范:TypePublicInternalModuleslower_with_under_lower_with_underPackageslower_with_underClassesCapWords_CapWordsExceptionsCapWordsFunctionslower_with_under()_lower_with_under()Global/ClassConstantsCAPS_WITH_UNDER_CAPS_WITH_UNDERGlobal/ClassVariableslower_with_under_lower_with_underInstanceVariableslower_with_under_lower_with_under(protected)or__lower_with_under(private)MethodNameslower_with_under()_lower_with_under()(protected)or__lower_with_under()(private)Function/MethodParameterslower_with_underLocalVariableslower_with_under二、編碼規(guī)范2.1三目運(yùn)算符2.1.1

【必須】

三目操作符判斷,python不支持三目運(yùn)算符,但可使用如下方式,禁止使用復(fù)雜難懂的邏輯判斷。正確示范x

=

a

if

a

>=

b

else

b錯誤示范x

=

a

>=

b

and

a

or

b2.2None條件的判斷2.2.1

【必須】

為提升可讀性,在判斷條件中應(yīng)使用

isnot,而不使用

not...is。pycodestyle:E714testforobjectidentityshouldbe'isnot'.正確示范if

foo

is

not

None:錯誤示范if

not

foo

is

None:2.3lambda匿名函數(shù)2.3.1

【必須】

使用def定義簡短函數(shù)而不是使用lambda。pycodestyle:E731donotassignalambdaexpression,useadef.使用def的方式有助于在trackbacks中打印有效的類型信息,明確使用

f

函數(shù)而不是一個lambda的調(diào)用。正確示范def

f(x):

return

2

*

x錯誤示范f

=

lambda

x:

2

*

x2.4異常2.4.1

【必須】

異常類繼承自

Exception,而不是

BaseException。2.4.2

【必須】

使用新版本拋出異常的方式,禁止使用廢棄的方式。pycodestyle:W602deprecatedformofraisingexception.正確示范raise

ValueError('message')錯誤示范raise

ValueError,

'message'2.4.3

【必須】

捕獲異常時,需要指明具體異常,而不是捕獲所有異常。除非已經(jīng)在當(dāng)前線程的最外層(記得還是要打印一條traceback)。pylint:broad-except,

bare-except.正確示范try:

import

platform_specific_module

except

ImportError:

platform_specific_module

=

None

try:

do_something()

except

Exception

as

ex:

#

pylint:

disable=broad-except

log.exception(ex)

#

應(yīng)將錯誤堆棧打印到日志文件中,以供后續(xù)排查。

handle_exception_or_not()

#

除打印日志外,還可以進(jìn)一步處理如清理資源等,可選。錯誤示范try:

import

platform_specific_module

except

Exception:

#

broad-except

platform_specific_module

=

None

try:

do_something()

except

Exception:

#

框架等未明確異常場景,建議增加

traceback

打印

pass2.4.4

【推薦】

建議在代碼中用異常替代函數(shù)的錯誤返回碼。正確示范def

write_data():

if

check_file_exist():

do_something()

else:

raise

FileNotExist()錯誤示范def

write_data():

if

check_file_exist():

do_something()

return

0

else:

return

FILE_NOT_EXIST2.4.5

【推薦】

except

子句中重新拋出原有異常時,不能用

raiseex,而是用

raise。正確示范try:

raise

MyException()

except

MyException

as

ex:

try_handle_exception()

raise

#

可以保留原始的

traceback

try:

raise

MyException()

except

MyException

as

ex:

log.exception(ex)

raise

AnotherException(str(ex))

#

允許的,建議保留好之前的異常棧信息,用于定位問題錯誤示范try:

raise

MyException()

except

MyException

as

ex:

try_handle_exception()

raise

ex

#

異常棧信息從這里開始,原始的raise異常棧信息消息2.4.6

【推薦】

所有

try/except

子句的代碼要盡可的少,以免屏蔽其他的錯誤。正確示范try:

value

=

collection[key]

except

KeyError:

return

key_not_found(key)

else:

return

handle_value(value)錯誤示范try:

#

范圍太廣

return

handle_value(collection[key])

except

KeyError:

#

會捕捉到

handle_value()

中的

KeyError

return

key_not_found(key)2.5條件表達(dá)式2.5.1

【推薦】

函數(shù)或者方法在沒有返回時要明確返回

None。pylint:inconsistent-return-statements.正確示范def

foo(x):

if

x

>=

0:

return

math.sqrt(x)

else:

return

None

def

bar(x):

if

x

<

0:

return

None

return

math.sqrt(x)錯誤示范def

foo(x):

if

x

>=

0:

return

math.sqrt(x)

def

bar(x):

if

x

<

0:

return

return

math.sqrt(x)2.5.2

【推薦】

對于未知的條件分支或者不應(yīng)該進(jìn)入的分支,建議拋出異常,而不是返回一個值(比如說

None

False)。正確示范def

f(x):

if

x

in

('SUCCESS',):

return

True

else:

raise

MyException()

#

如果一定不會走到的條件,可以增加異常,防止將來未知的語句執(zhí)行。錯誤示范def

f(x):

if

x

in

('SUCCESS',):

return

True

return

None2.5.3

【可選】

if

else

盡量一起出現(xiàn),而不是全部都是

if

子句。正確示范if

condition:

do_something()

else:

#

增加說明注釋

pass

if

condition:

do_something()

#

這里增加注釋說明為什么不用寫else子句

#

else:

#

pass錯誤示范if

condition:

do_something()

if

another_condition:

#

不能確定是否筆誤為

elif

,還是開啟全新一個if條件

do_another_something()

else:

do_else_something()2.6True/False布爾運(yùn)算2.6.1

【必須】

不要用

==

True、

False

進(jìn)行布爾運(yùn)算。pylint:singleton-comparison.正確示范if

greeting:

pass錯誤示范if

greeting

==

True:

pass

if

greeting

is

True:

#

Worse

pass2.6.2

【必須】

對序列(字符串、列表、元組),空序列為false的情況。pylint:len-as-condition.正確示范if

not

seq:

pass

if

seq:

pass錯誤示范if

len(seq):

pass

if

not

len(seq):

pass2.7列表推導(dǎo)式2.7.1

【必須】

禁止超過1個for語句或過濾器表達(dá)式,否則使用傳統(tǒng)

for

循環(huán)語句替代。正確示范number_list

=

[1,

2,

3,

10,

20,

55]

odd

=

[i

for

i

in

number_list

if

i

%

2

==

1]

result

=

[]

for

x

in

range(10):

for

y

in

range(5):

if

x

*

y

>

10:

result.append((x,

y))錯誤示范result

=

[(x,

y)

for

x

in

range(10)

for

y

in

range(5)

if

x

*

y

>

10]

#

for

語句2.7.2

【推薦】

列表推導(dǎo)式適用于簡單場景。如果語句過長,每個部分應(yīng)該單獨(dú)置于一行:映射表達(dá)式,for語句,過濾器表達(dá)式。正確示范fizzbuzz

=

[]

for

n

in

range(100):

if

n

%

3

==

0

and

n

%

5

==

0:

fizzbuzz.append(f'fizzbuzz

{n}')

elif

n

%

3

==

0:

fizzbuzz.append(f'fizz

{n}')

elif

n

%

5

==

0:

fizzbuzz.append(f'buzz

{n}')

else:

fizzbuzz.append(n)

for

n

in

range(1,

11):

print(n)錯誤示范#

條件過于復(fù)雜,應(yīng)該采用for語句展開

fizzbuzz

=

[

f'fizzbuzz

{n}'

if

n

%

3

==

0

and

n

%

5

==

0

else

f'fizz

{n}'

if

n

%

3

==

0

else

f'buzz

{n}'

if

n

%

5

==

0

else

n

for

n

in

range(100)

]

[print(n)

for

n

in

range(1,

11)]

#

無返回值2.8函數(shù)2.8.1

【必須】

模塊內(nèi)部禁止定義重復(fù)函數(shù)聲明。pylint:function-redefined.禁止重復(fù)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論