中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
教你寫出可讀性高的Python代碼

作者:Python 最佳實踐指南 2018 
來源:https://learnku.com/docs/python-guide/2018/writing-style/3261

如果有人問起 Python 程序員他們最喜歡 Python 哪一點,他們一定會提到 Python 的高可讀性。確實,對于 Python 來說,其高可讀性一直是 Python 這門語言設(shè)計的核心。一個不爭的事實是,相對于寫代碼而言,讀代碼才是更加平常的事情。

Python 代碼有高可讀性的一個原因就是其有著相對而言更加完善的編碼風(fēng)格準(zhǔn)則和 「Python 化」習(xí)慣語法。

當(dāng) Python 老手(Pythonista)認(rèn)為一段代碼不「Python 化」,他們通常的意思是這段代碼沒有遵循一般準(zhǔn)則,同時亦沒有以最佳的(最具可讀性的)方式表達(dá)出代碼的意圖。

在一些極端的情況下,沒有公認(rèn)最佳的方式來表達(dá) Python 代碼的意圖,不過這種極端情況非常罕見。

一般概念

明確代碼意義

盡管 Python 可以寫出從各種意義上來說都像是黑魔法的代碼,但最簡單直白的表達(dá)才是正道。

不優(yōu)雅

def make_complex(*args):
    x, y = args
    return dict(**locals())

優(yōu)雅

def make_complex(x, y):
    return {'x': x, 'y': y}

在上述好的代碼中,x 和 y 清晰明了的從參數(shù)中獲取值,并清晰明了的返回了一個字典。當(dāng)開發(fā)者看到這個函數(shù)后就可以明了這個函數(shù)的用途,而不好的代碼則不行。

一行一個聲明語句

雖然在 Python 中我們推崇使用形如列表生成式這種簡潔明了的復(fù)合語句,但是除此以外,我們應(yīng)該盡量避免將兩句獨立分割的代碼寫在同一行。

不好的風(fēng)格

print 'one'; print 'two'

if x == 1: print 'one'

if <complex comparison> and <other complex comparison>:
    # do something

好的風(fēng)格

print 'one'
print 'two'

if x == 1:
    print 'one'

cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
    # do something

函數(shù)的參數(shù)

函數(shù)的參數(shù)可以使用四種不同的方式傳遞給函數(shù)。

  1. 必選參數(shù) 是沒有默認(rèn)值的必填的參數(shù)。必選參數(shù)是最簡單的參數(shù)構(gòu)成,用于參數(shù)較少的函數(shù)的構(gòu)成,是該函數(shù)意義的一部分,使用他們的順序是按照定義自然排序的。舉個例子,對于 send(message, recipient) 和  point(x, y) 這兩個函數(shù),使用函數(shù)的人需要知道這個函數(shù)需要兩個參數(shù),并且記住兩個參數(shù)的順序。

在調(diào)用函數(shù)的時候,我們也可以使用參數(shù)的名稱調(diào)用。使用參數(shù)的名稱的方式可以調(diào)換參數(shù)的順序,就像 send(recipient='World',message='Hello')point(y=2, x=1) 這樣。但這樣的做法會降低代碼的可讀性,并且使代碼冗長,因此更建議使用 send('Hello', 'World')point(1,2) 這樣的方式調(diào)用。

  1. 關(guān)鍵字參數(shù) 是非強制的,且有默認(rèn)值。它們經(jīng)常被用在傳遞給函數(shù)的可選參數(shù)中。當(dāng)一個函數(shù)有超過兩個或三個位置參數(shù)時,函數(shù)簽名會變得難以記憶,使用帶有默認(rèn)參數(shù)的關(guān)鍵字參數(shù)有時候會給你帶來便利。比如,一個更完整的 send 函數(shù)可以被定義為 send(message, to, cc=None, bcc=None)。這里的 ccbcc 是可選的, 當(dāng)沒有傳遞給它們其他值的時候,它們的值就是 None。

Python 中有多種方式調(diào)用帶關(guān)鍵字參數(shù)的函數(shù)。比如說,我們可以按照定義時的參數(shù)順序而無需明確的命名參數(shù)來調(diào)用函數(shù),就像 send('Hello', 'World', 'Cthulhu', 'God') 是將密件發(fā)送給上帝。我們也可以使用命名參數(shù)而無需遵循參數(shù)順序來調(diào)用函數(shù),就像 send('Hello again', 'World', bcc='God', cc='Cthulhu') 。沒有特殊情況的話,這兩種方式都需要盡力避免,最優(yōu)的調(diào)用方式是與定義方式一致:send('Hello', 'World', cc='Cthulhu',bcc='God') 。

作為附注,請遵循 YAGNI 原則。通常,移除一個用作『以防萬一』但從未使用的可選參數(shù)(以及它在函數(shù)中的邏輯),比添加一個所需的新的可選參數(shù)和它的邏輯要來的困難。

  1. 任意參數(shù)列表 是第三種給函數(shù)傳參的方式。如果函數(shù)的參數(shù)數(shù)量是動態(tài)的,該函數(shù)可以被定義成 *args 的結(jié)構(gòu)。在這個函數(shù)體中, args 是一個元組,它包含所有剩余的位置參數(shù)。舉個例子, 我們可以用任何容器作為參數(shù)去調(diào)用 send(message, *args) ,比如 send('Hello', 'God', 'Mom','Cthulhu')。在此函數(shù)體中, args 相當(dāng)于 ('God','Mom', 'Cthulhu')。

然而,這種結(jié)構(gòu)有一些缺點,使用時應(yīng)該特別注意。如果一個函數(shù)接受的參數(shù)列表具有相同的性質(zhì),通常把它定義成一個參數(shù),這個參數(shù)是一個列表或者其他任何序列會更清晰。在這里,如果 send 參數(shù)有多個容器(recipients),將之定義成 send(message,recipients) 會更明確,調(diào)用它時就使用 send('Hello', ['God', 'Mom', 'Cthulhu'])。這樣的話, 函數(shù)的使用者可以事先將容器列表維護(hù)成列表(list)形式,這為傳遞各種不能被轉(zhuǎn)變成其他序列的序列(包括迭代器)帶來了可能。

  1. 任意關(guān)鍵字參數(shù)字典 是最后一種給函數(shù)傳參的方式。如果函數(shù)要求一系列待定的命名參數(shù),我們可以使用 **kwargs 的結(jié)構(gòu)。在函數(shù)體中, kwargs 是一個字典,它包含所有傳遞給函數(shù)但沒有被其他關(guān)鍵字參數(shù)捕捉的命名參數(shù)。

任意參數(shù)列表 中所需注意的一樣,相似的原因是:這些強大的技術(shù)在非特殊情況下,都要盡量避免使用,因為其缺乏簡單和明確的結(jié)構(gòu)來足夠表達(dá)函數(shù)意圖。

編寫函數(shù)的時候采用何種參數(shù)形式,是用位置參數(shù),還是可選關(guān)鍵字參數(shù),是否使用形如任意參數(shù) 的高級技術(shù),這些都由程序員自己決定。如果能明智地遵循上述建議,即可輕松寫出這樣的 Python 函數(shù):

  • 易讀(名字和參數(shù)無需解釋)

  • 易改(添加新的關(guān)鍵字參數(shù)不會破壞代碼的其他部分)

避免魔法方法

Python 對駭客來說是一個強有力的工具,它擁有非常豐富的鉤子(hook)和工具,允許你施展幾乎任何形式的技巧。比如說,它能夠做以下:

  • 改變對象創(chuàng)建和實例化的方式;

  • 改變 Python 解釋器導(dǎo)入模塊的方式;

  • 甚至可能(如果需要的話也是被推薦的)在 Python 中嵌入 C 程序。

盡管如此,所有的這些選擇都有許多缺點。使用最直接的方式來達(dá)成目標(biāo)通常是最好的方法。它們最主要的缺點是可讀性不高。許多代碼分析工具,比如說 pylint 或者 pyflakes,將無法解析這種『魔法』代碼。

我們認(rèn)為 Python 開發(fā)者應(yīng)該知道這些近乎無限的可能性,因為它為我們灌輸了沒有不可能完成的任務(wù)的信心。然而,知道何時 不能 使用它們也是非常重要的。

就像一位功夫大師,一個 Pythonista 知道如何用一個手指殺死對方,但從不會那么去做。

我們都是負(fù)責(zé)任的用戶

如前所述,Python 允許很多技巧,其中一些具有潛在的危險。一個好的例子是:任何客戶端代碼能夠重寫一個對象的屬性和方法(Python 中沒有 private 關(guān)鍵字)。這種哲學(xué)是在說:『我們都是負(fù)責(zé)任的用戶』,它和高度防御性的語言(如 Java,擁有很多機制來預(yù)防錯誤操作)有著非常大的不同。

這并不意味著,比如說,Python 中沒有屬性是私有的,也不意味著沒有合適的封裝方法。與其依賴在開發(fā)者的代碼之間樹立起的一道道隔墻,Python 社區(qū)更愿意依靠一組約定,來表明這些元素不應(yīng)該被直接訪問。

私有屬性的主要約定和實現(xiàn)細(xì)節(jié)是在所有的 內(nèi)部 變量前加一個下劃線。如果客戶端代碼打破了這條規(guī)則并訪問了帶有下劃線的變量,那么因內(nèi)部代碼的改變而出現(xiàn)的任何不當(dāng)?shù)男袨榛騿栴},都是客戶端代碼的責(zé)任。

鼓勵大方地使用此約定:任何不開放給客戶端代碼使用的方法或?qū)傩?,?yīng)該有一個下劃線前綴。這將保證更好的職責(zé)劃分以及更容易對已有代碼進(jìn)行修改。將一個私有屬性公開化總是可能的,但是把一個公共屬性私有化可能是一個更難的選擇。

返回值

當(dāng)一個函數(shù)變得復(fù)雜,在函數(shù)體中使用多返回值的語句并不少見。然而,為了保持函數(shù)的可讀性,建議在函數(shù)體中避免使用返回多個有意義的值。

在函數(shù)中返回結(jié)果主要有兩種情況:函數(shù)正常運行并返回它的結(jié)果,以及錯誤的情況,要么因為一個錯誤的輸入?yún)?shù),要么因為其他導(dǎo)致函數(shù)無法完成計算或任務(wù)的原因。

如果你在面對第二種情況時不想拋出異常,返回一個值(比如說 None 或 False )來表明函數(shù)無法正確運行,可能是需要的。在這種情況下,越早返回所發(fā)現(xiàn)的不正確上下文越好。這將幫助扁平化函數(shù)的結(jié)構(gòu):我們假定在『因為錯誤而返回』的語句后的所有代碼都能夠滿足函數(shù)主要結(jié)果運算。這種類型的多發(fā)揮結(jié)果,是有必要的。

然而,當(dāng)一個函數(shù)在其正常運行過程中有多個主要出口點時,它會變得難以調(diào)試其返回結(jié)果,所以保持單個出口點可能會更好。這也將有助于提取某些代碼路徑,而且多個出口點很有可能意味著這里需要重構(gòu):

def complex_function(a, b, c):
    if not a:
        return None  # 拋出一個異??赡軙?br>    if not b:
        return None  # 拋出一個異常可能會更好

    # 一些復(fù)雜的代碼試著用 a,b,c 來計算x
    # 如果成功了,抵制住返回 x 的誘惑
    if not x:
        # 使用其他的方法來計算出 x
    return x  # 返回值 x 只有一個出口點有利于維護(hù)代碼

習(xí)語(Idiom)

編程習(xí)語,說得簡單些,就是寫代碼的 方式。編程習(xí)語的概念在 c2 和 Stack Overflow 上有詳盡的討論。

符合習(xí)語的 Python 代碼通常被稱為 Pythonic。

通常只有一種、而且最好只有一種明顯的方式去編寫代碼。對 Python 初學(xué)者來說,無意識的情況下很少能寫出習(xí)語式 Python 代碼,所以應(yīng)該有意識地去獲取習(xí)語的書寫方式。

如下有一些常見的 Pythonic

解包(Unpacking)

如果你知道一個列表或者元組的長度,你可以將其解包并為它的元素取名。比如,enumerate() 會對 list 中的每個項提供包含兩個元素的元組:

for index, item in enumerate(some_list):
    # do something with index and item

你也能通過這種方式交換變量:

a, b = b, a

嵌套解包也能工作:

a, (b, c) = 1, (2, 3)

Python 3 提供了擴展解包的新方法在 PEP 3132 有介紹:

a, *rest = [1, 2, 3]
# a = 1, rest = [2, 3]
a, *middle, c = [1, 2, 3, 4]
# a = 1, middle = [2, 3], c = 4

創(chuàng)建一個被忽略的變量

如果你需要賦值(比如,在 解包(Unpacking) )但不需要這個變量,請使用 __:

filename = 'foobar.txt'
basename, __, ext = filename.rpartition('.')

注意

許多 Python 風(fēng)格指南建議使用單下劃線的 _ 而不是這里推薦的雙下劃線 __ 來標(biāo)記廢棄變量。問題是, _常用在作為 gettext() 函數(shù)的別名,也被用在交互式命令行中記錄最后一次操作的值。相反,使用雙下劃線 十分清晰和方便,而且能夠消除使用其他這些用例所帶來的意外干擾的風(fēng)險。

創(chuàng)建一個含 N 個對象的列表

使用 Python 列表中的 * 操作符:

four_nones = [None] * 4

創(chuàng)建一個含 N 個列表的列表

因為列表是可變的,所以 * 操作符(如上)將會創(chuàng)建一個包含 N 個且指向 同一個 列表的列表,這可能不是你想用的。取而代之,請使用列表解析:

four_lists = [[] for __ in xrange(4)]

注意:在 Python 3 中使用 range() 而不是 xrange()。

根據(jù)列表來創(chuàng)建字符串

創(chuàng)建字符串的一個常見習(xí)語是在空的字符串上使用 str.join()

letters = ['s', 'p', 'a', 'm']
word = ''.join(letters)

這會將 word 變量賦值為 spam。這個習(xí)語可以用在列表和元組中。

在集合體(collection)中查找一個項

有時我們需要在集合體中查找。讓我們看看這兩個選擇,列表和集合(set),用如下代碼舉個例子:

s = set(['s', 'p', 'a', 'm'])
l = ['s', 'p', 'a', 'm']

def lookup_set(s):
    return 's' in s

def lookup_list(l):
    return 's' in l

即使兩個函數(shù)看起來完全一樣,但因為 查找集合 是利用了 Python 中的『集合是可哈?!坏奶匦?,兩者的查詢性能是非常不同的。為了判斷一個項是否在列表中,Python 將會查看每個項直到它找到匹配的項。這是耗時的任務(wù),尤其是對長列表而言。另一方面,在集合中, 項的哈希值將會告訴 Python 在集合的哪里去查找匹配的項。結(jié)果是,即使集合很大,查詢的速度也很快。在字典中查詢也是同樣的原理。想了解更多內(nèi)容,請見 StackOverflow 。想了解在每種數(shù)據(jù)結(jié)構(gòu)上的多種常見操作的花費時間的詳細(xì)內(nèi)容, 請見 此頁面。

因為這些性能上的差異,在下列場景中,使用集合或者字典而不是列表,通常會是個好主意:

  • 集合體中包含大量的項;

  • 你將在集合體中重復(fù)地查找項;

  • 你沒有重復(fù)的項。

對于小的集合體、或者你不會頻繁查找的集合體,建立哈希帶來的額外時間和內(nèi)存的開銷經(jīng)常會大過改進(jìn)搜索速度所節(jié)省的時間。

約定

這里有一些你應(yīng)該遵循的約定,以讓你的代碼更加易讀。

檢查變量是否等于常量

你不需要明確地比較一個值是 True,或者 None,或者 0 - 你可以僅僅把它放在 if 語句中。參閱 真值測試 來了解什么被認(rèn)為是 false:

糟糕:

if attr == True:
    print 'True!'

if attr == None:
    print 'attr is None!'

優(yōu)雅:

# 檢查值
if attr:
    print 'attr is truthy!'

# 或者做相反的檢查
if not attr:
    print 'attr is falsey!'

# 或者,None 等于 false,你可以直接相較它進(jìn)行匹配
if attr is None:
    print 'attr is None!'


訪問字典元素

不要使用 dict.has_key() 方法。相反,使用 x in d 語法,或者將默認(rèn)參數(shù)傳遞給 dict.get() 方法。

壞的示例

d = {'hello': 'world'}
if d.has_key('hello'):
    print d['hello']    # prints 'world'
else:
    print 'default_value'

推薦的示例:

d = {'hello': 'world'}

print d.get('hello', 'default_value') # prints 'world'
print d.get('thingy', 'default_value') # prints 'default_value'

# 或者:
if 'hello' in d:
    print d['hello']


操作列表的簡便方法

列表推導(dǎo)式 提供了一個強大并且簡潔的方法來對列表價進(jìn)行操作。除此之外,map()filter()  函數(shù)在列表的操作上也是非常簡潔的。

:

# Filter elements greater than 4
a = [3, 4, 5]
b = []
for i in a:
    if i > 4:
        b.append(i)

:

a = [3, 4, 5]
b = [i for i in a if i > 4]
# Or:
b = filter(lambda x: x > 4, a)

:

# Add three to all list members.
a = [3, 4, 5]
for i in range(len(a)):
    a[i] += 3

:

a = [3, 4, 5]
a = [i + 3 for i in a]
# Or:
a = map(lambda i: i + 3, a)

使用 enumerate() 來跟蹤正在被處理的元素索引。

a = [3, 4, 5]
for i, item in enumerate(a):
    print i, item
# prints
# 0 3
# 1 4
# 2 5

比起手動計數(shù),使用 enumerate() 函數(shù)有更好的可讀性,而且,他更加適合在迭代器中使用。

讀文件

使用 with open 語法來讀文件,它能夠為你自動關(guān)閉文件。

:

f = open('file.txt')
a = f.read()
print a
f.close()

:

with open('file.txt') as f:
    for line in f:
        print line

即使在 with 控制塊中出現(xiàn)了異常,它也能確保你關(guān)閉了文件,因此,使用 with 語法是更加優(yōu)雅的。

行的延續(xù)

當(dāng)一個代碼邏輯行的長度超過可接受的限度時,你需要將之分為多個物理行。如果行的結(jié)尾是一個反斜杠,Python 解釋器會把這些連續(xù)行拼接在一起。這在某些情況下很有幫助, 但我們總是應(yīng)該避免使用,因為它的脆弱性:如果在行的結(jié)尾,在反斜杠后加了空格,這會破壞代碼,而且可能有意想不到的結(jié)果。

一個更好的解決方案是在元素周圍使用括號。左邊以一個未閉合的括號開頭,Python 解釋器會把行的結(jié)尾和下一行連接起來直到遇到閉合的括號。同樣的行為適用中括號和大括號。

糟糕

my_very_big_string = '''For a long time I used to go to bed early. Sometimes,\
    when I had put out my candle, my eyes would close so quickly that I had not even\
    time to say 'I'm going to sleep.''''

from some.deep.module.inside.a.module import a_nice_function, another_nice_function,\
    yet_another_nice_function

優(yōu)雅

my_very_big_string = (
    'For a long time I used to go to bed early. Sometimes, '
    'when I had put out my candle, my eyes would close so quickly '
    'that I had not even time to say 'I'm going to sleep.''
)

from some.deep.module.inside.a.module import (
    a_nice_function, another_nice_function, yet_another_nice_function)

盡管如此,通常情況下,必須去分割一個長邏輯行意味著你同時想做太多的事,這可能影響可讀性。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Python申明參數(shù),提高代碼可讀性
怎樣讓你寫的Python代碼更優(yōu)雅?
Python 初學(xué)筆記 - 第一章-變量與注釋
無壓力,輕松學(xué)會Python的裝飾器
[Python]年度黑馬Python 自省指南
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服