Python 代碼風格

1 原則

在開始討論Python社區所採用的具體標準或是由其餘人推薦的建議以前,考慮一些整體原則很是重要。python

請記住可讀性標準的目標是提高可讀性。這些規則存在的目的就是爲了幫助人讀寫代碼,而不是相反。算法

本小節討論你所需記住的一些原則。數據庫

1.1 假定你的代碼須要維護

人們很容易傾向相信某時所完成的工做在將來不須要添加一部分或對其維護。這是因爲很難預料到將來的需求,以及低估本身形成Bug的傾向。然而,所寫代碼不多不被修改一直存在。編程

若是你假設本身所寫代碼會一勞永逸的無需以後進行閱讀、調試或修補,那麼你就會很是容易陷入忽視其餘可讀性原則的境地,這僅僅是由於你相信此次並不重要app

所以,保持對本身感受所寫代碼無需維護的直覺的不信任纔是上策。穩賺不賠的辦法是賭本身將會再次見到本身寫的代碼。即便你不維護,那也須要其餘人維護。框架

1.2 保持一致性

一致性的兩個方面分別爲:內部一致性和外部一致性。ide

不管是從代碼風格和代碼結構層面來說,代碼都要儘可能知足內部一致性。不管是哪一種格式化規則,代碼風格都要貫穿項目保持一致。代碼結構的一致性也就是一樣類型的代碼放到一塊兒。這樣項目容易把控。函數

代 碼還應該保持外部一致性。項目與代碼的結構與其餘人保持一致,若是一個新來的開發人員打開你的項目,你不該該讓他的反應是:我歷來沒見過像這樣的東 西。社區指導原則很重要,由於這就是開發人員加入到你的項目預期所見。相似的,以及相同的緣由,請認真看待在使用特定框架時完成任務以及組織代碼所採用 的標準。工具

1.3 考慮事物存在方式,尤爲是帶有數據

存在論(Ontology)的主要意思就是關於存在的研究。在哲學上(在該領域這個詞很經常使用)存在論是關於現實與存在本質的研究,是形而上學的子集。網站

而對於寫軟件程序來講,存在論指的是關注不一樣事物在程序中如何存在。你如何將概念轉化爲在數據庫中表示?亦或是用類結構表示?

這類問題最終影響你編寫或組織代碼的方式。是否使用繼承或是組合來組織兩個類之間的關係?數據庫中用哪一個表完成這項功能或是這個列屬於誰?

這些建議最終歸結爲在寫代碼以前先思考。尤爲是思考程序但願實現的目標,以及程序之間如何交互。程序是一個對象與數據交互的世界。那麼,它們之間協做所需遵循的規則是什麼?

1.4 不要作重複工做

當編寫代碼時,請考慮隨着時間重複使用的值將會變動的狀況。該值是否被用於多個模塊或函數中?若是必要,須要花費多大代價修改它?

一樣的原則適用於函數。你是否在程序中有大量的重複的代碼?若是這些重複代碼行數較多,能夠考慮將其抽象到一個函數中,若是出現修改代碼的需求,則更容易管理。

另外一方面,對於該原則不要過猶不及。並非全部值都須要在模塊中定義爲常量(這麼作會損害可讀性和可維護性)。請明智判斷,不斷問這樣一個問題:若是須要變動該代碼,變動該代碼的全部位置所須要的成本是多少

1.5 讓註釋講故事

代碼是一個故事。它是所發生故事的說明,在用戶與程序交互過程當中,從開始到結束。程序從某一點開始(可能帶有一些輸入),沿着一系列選擇本身的冒險故事步驟到達終點,並結束(極可能帶有一些輸出結果)。

採用的註釋風格能夠是每一些行代碼以前就添加一段註釋,用於解釋代碼的功能。若是代碼是一個故事,那麼註釋就是故事的解釋與旁白。

若是敘事式註釋作的很好,讀者就能夠經過閱讀註釋瞭解故事,從而解析代碼(例如,當嘗試解決問題或維護代碼時),而後能夠從零開始快速瞭解所需維護的代碼,這樣就能夠專一於代碼自己所表明的意義。

敘事式註釋還能夠幫助解釋代碼意圖。它能夠回答這樣的問題:寫這段代碼的人但願完成的目標是什麼?偶爾,還能夠幫助回答問題:爲何以這種方式完成工做?這些問題是在你閱讀代碼時很天然會問的,爲這些問題提供答案將會幫助瞭解這些內容。

所以,註釋用於解釋代碼中不顯而易見或複雜部分的原理。若是使用了有點複雜的算法,請考慮將指向解釋模式文章的連接以及其餘使用示例加入註釋。

1.6 奧卡姆剃刀原則

編 寫可維護代碼最重要的原則通俗來說就是奧卡姆剃刀原則:最簡單的解決方案一般是最好的。在他的「Python之禪博文 (https://www.python.org/dev/peps/pep-0020/),該頁面是編程格言的集合(例如,在Python控制檯中輸入 「import this」就能夠看到這篇),Tim Peters也包括了相似下面這句若是你沒法向人描述你的方案,那確定不是一個好方案

上述原則在代碼如何運行與代碼外觀層面都生效。當提到代碼運行時,簡單的系統更加容易維護。實現的簡單化意味着更少引入複雜的BUG,哪些維護你代碼的人(包括你本身)更容易憑直覺理解代碼所表明的含義,並在不踩坑的前提下爲程序增長代碼。

至 於代碼的外觀,請記住,儘量使得閱讀代碼就好像是在瞭解代碼所作工做的故事,而不是爲了解析詞彙。詞彙是手段,而故事纔是最終目的。寫一條諸如不要使 用三元運算符很容易。然而僅僅是遵循這些規則(雖然有價值)並非代碼明晰的充分條件。請專一以儘量簡潔的方式編寫和組織代碼

2 標準

Python社區大部分遵循所謂的PEP 8https://www.python.org/
dev/peps/pep-0008/
)指導原則,由Guido van RossumPython之父)編寫並被包括Python標準庫中的大多數主流Python項目採用。

PEP 8的廣泛性是其強大的緣由之一。該標準被大多數社區項目採納,所以你能夠預計大多數你遇到的Python代碼都遵循該標準。當你以這種方式編寫代碼時,代碼會更加容易閱讀,也更容易編寫。

2.1 簡潔的規則

大多數PEP 8中的指導原則都很簡單明瞭。部分重點以下:

l 使用4個空格縮進。不要使用製表符(\t)。

l 變量應該使用下劃線鏈接,不使用駱駝式命名風格(使用my_var而不是myVar)。類名稱以字母開頭就是駱駝式命名風格(例如:MyClass)。

l 若是一個變量的用處是:僅內部使用,在變量名稱以前加上下劃線。

l 在運算符先後加上單空格(例如,x + y,不是x+y),也包含賦值運算符(z = 3而不是z=3),只有在關鍵字參數狀況下不適用,在這種狀況下,空格能夠省略。

l 在列表和字典中省略沒必要要的括號,(例如: [1, 1, 2, 3, 5],而不是[ 1, 1, 2, 3, 5 ])。
請閱讀Python代碼風格指南得到更多示例以及有關這些規則的更多討論。

2.2 文檔字符串

請記住,在Python中,若是在一個函數或類中第一個語句是一個字符串,該字符串會自動賦值給一個特殊的「_doc_」變量,該變量在調用Help(和一些其餘的類)時會被使用。

PEP 8 規定文檔字符串(該名稱能夠被望文生義)是必須的。

"""Do X, Y, and Z, then return the result."""

該句子與做爲描述的文檔字符串的對比:

"""Does X, Y, and Z, then returns the result."""

若是文檔字符串是一行,那麼須要在類或函數體以前加空行。若是文檔字符串有多行,則將結束的雙引號單獨放一行。

2.3 空行

空行用於邏輯分塊。

PEP8規定最高級的類和函數定義之間有兩個空行。

class A(object):
pass

class B(object):
pass

代碼清單1.

PEP 8還規定除了最高級以外,類和函數的定義以一個空行分隔。

class C(object):

def foo(self):

pass

def bar(self):

pass 

代碼清單2.

在函數或其餘代碼段中使用單空行分隔邏輯段是合理的。請考慮在邏輯段以前使用註釋解釋代碼段的做用。

2.4 導入

Python容許絕對路徑導入和相對路徑導入。在Python2中,解釋器會嘗試相對導入,若是找不到路徑,而後再嘗試使用絕對導入。

Python 3中,使用特殊語法標記相對當如----以(.)開頭----「正常的導入方式只會嘗試相對路徑。Python 3的語法在Python 2.6之後版本可使用。除此以外你可使用—「_future_」關閉隱式相對路徑導入。

若是可能,儘可能使用絕對路徑導入。若是不得不使用相對路徑,請使用顯式導入風格。若是你爲Python 2.6 2.7編寫代碼,請考慮選擇Python 3中的顯式風格。

當導入模塊時,每一個模塊單獨佔一行。

import os
import sys

代碼清單3

然而,若是你從同一個模塊中導入多個名稱,固然能夠將這些名稱分組到一行中。

from datetime import date, datetime, timedelta

 

代碼清單4

除此以外,雖然PEP 8並無強制要求,考慮以包來源的方式將導入分組。對於每一組,按照字母表順序排序。

另外,在導入時,請不要忘了使用as關鍵字給導入的內容起別名。

from foo.bar import really_long_name as name

代碼清單5

這使得你能夠簡化被頻繁使用的長名稱或不規範命名的名稱。

當導入被頻繁使用且原始名稱不管何種緣由不規範時,別名就頗有價值了。

另外一方面,請記住當你這麼作時,你會在你的模塊中掩蓋了原始名稱,若是不必使用別名,這會使得代碼變得不清晰。不管是使用何種工具,要作到具體狀況,具體分析。

2.5 變量

正如以前所提到的,變量名稱使用下劃線鏈接,而不要使用駱駝代碼風格(例如,my_val而不是myVal)。除此以外,起一個具備描述性的名稱一樣重要。

一般狀況下使用很是短的變量名稱並不合適,雖然某些狀況下這麼作也能接受,好比在循環中的變量(例如,for k in mydict_item())。

避免命名的函數名稱與Python語言中的經常使用名稱重複,就算是解釋器容許也不行。不管在任何狀況下,都不要命名某個對象爲sumprint。相似的,避免listdict之類的名稱。

如 果你必需要命名一個與Python類型與關鍵字同名的變量,慣例是在變量名稱以後加下劃線;相比修更名稱的拼寫來講,這麼作更加可取。例如,若是你將一個 類做爲參數傳遞給一個函數,那麼參數名稱應該爲class_,而不是klass(一個例外是靜態方法,按照慣例使用cls做爲第一個參數)。

2.6 註釋

註釋應該使用英語寫完整的句子(譯者注:固然在國內這點值得商榷),放在相關的代碼以前。正確使用首字母大寫和語法,以及保證拼寫正確。

同時,保證註釋最新。若是代碼變動,那麼註釋可能也須要隨之變動。你應該不但願註釋與代碼表示的意思相反,這很容易致使混淆。

模塊可能包含一個註釋頭,一般由版本控制系統生成,其中包含文件版本的信息。這使得發現文件被修改變得容易,尤爲是在將模塊分發給別人使用時。

2.7 行長度

Python代碼風格最有爭議(也是最常被拒絕使用的)的方面是對行長度的限制。PEP 8要求行長度不超過79個字符,文檔字符串不超過72個字符。

該規則讓不少開發人員感到沮喪,這些開發人員認爲咱們生活在一個27寸寬屏顯示器的時代。GitHub是一個很是流行共享代碼的網站,所使用的窗口寬度是120個字符。

而該規則的支持者指出不少人依然使用窄屏或80字符長度的終端,甚至僅僅是將代碼窗口的寬度設置爲小於屏幕寬度。

爭論很難有一個結果。總之,不管是遵循79字符寬度的標準或是更寬的標準,你應該按照項目標準的規範編碼。當行長度過長時,你應該知道如何處理代碼。

使用圓括號是封裝單行長代碼的最佳方式,以下所示:

if (really_long_identifier_that_maybe_should_be_shorter and
other_really_long_identifier_that_maybe_should_be_shorter):
do_something()

 

代碼清單6

只要可能,使用該方法,而不是在換行符以前使用 \字符。注意在使用諸如and之類的操做符時,儘量將其置於換行符以前。

封裝函數調用也是能夠的。PEP 8列出了許多可接受的方式完成封裝。通常規則是使得同級別行縮進保持一致。

really_long_function_name(

categories=[

x.y.COMMON_PHRASES,

x.y.FONT_PREVIEW_PHRASES,

],

phrase='The quick brown fox jumped over the lazy dogs.',

)

 

代碼清單7

當在函數調用、列表或字典中分行時,在行結尾部分添加逗號。

3 小結

大多數時候,一年後閱讀你代碼的人就是你本身。記憶並不像一開始時那麼好用。在編寫代碼時沒有留心代碼的可讀性與可維護性天然會使得代碼難以閱讀和維護。

通觀本書,你學會了如何使用Python中多種模塊、類與結構。當須要決定如何解決問題時,請記住調試代碼比寫代碼更有技術含量。

所以,以代碼儘量簡潔和可讀爲目標。一年後的你將會感謝本身。固然,你的同事以及下屬也會感謝你。

------本篇結選自本人翻譯的書《Python 高級編程》, 清華大學出版社-------------------------------------------------------------------------------------------------

相關文章
相關標籤/搜索