python_命名規(guī)范_基于PEP-8

Python庫的命名規(guī)范很亂,從來沒能做到完全一致。但是目前有一些推薦的命名標(biāo)準(zhǔn)。新的模塊和包(包括第三方框架)應(yīng)該用這套標(biāo)準(zhǔn),但當(dāng)一個已有庫采用了不同的風(fēng)格,推薦保持內(nèi)部一致性。

Overriding Principle 最重要的原則

那些暴露給用戶的API接口的命名,應(yīng)該遵循反映使用場景而不是實現(xiàn)的原則。

Descriptive: Naming Styles 描述:命名風(fēng)格

有許多不同的命名風(fēng)格。這里能夠幫助大家識別正在使用什么樣的命名風(fēng)格,而不考慮他們?yōu)槭裁词褂谩?br> 以下是常見的命名方式:

  • b(單個小寫字母)

  • B(單個大寫字母)

  • lowercase 小寫字母

  • lower_case_with_underscores 使用下劃線分隔的小寫字母

  • UPPERCASE 大寫字母

  • UPPER_CASE_WITH_UNDERSCORES 使用下劃線分隔的大寫字母

  • CapitalizedWords(或者叫 CapWords,或者叫CamelCase 駝峰命名法 —— 這么命名是因為字母看上去有起伏的外觀5)。有時候也被稱為StudlyCaps。
    注意:當(dāng)在首字母大寫的風(fēng)格中用到縮寫時,所有縮寫的字母用大寫,因此,HTTPServerErrorHttpServerError 好。

  • mixedCase(不同于首字母大寫,第一個單詞的首字母小寫)

  • Capitalized_Words_With_Underscores(巨丑無比!)

也有用唯一的短前綴把相關(guān)命名組織在一起的方法。這在Python中不常用,但還是提一下。比如,os.stat()函數(shù)中包含類似以st_mode,st_size,st_mtime這種傳統(tǒng)命名方式命名的變量。(這么做是為了與 POSIX 系統(tǒng)的調(diào)用一致,以幫助程序員熟悉它。)
X11庫的所有公共函數(shù)都加了前綴X。在Python里面沒必要這么做,因為屬性和方法在調(diào)用的時候都會用類名做前綴,函數(shù)名用模塊名做前綴。
另外,下面這種用前綴或結(jié)尾下劃線的特殊格式是被認(rèn)可的(通常和一些約定相結(jié)合):

  • _single_leading_underscore:(單下劃線開頭)弱“內(nèi)部使用”指示器。比如 from M import * 是不會導(dǎo)入以下劃線開始的對象的。

  • single_trailing_underscore_:(單下劃線結(jié)尾)這是避免和Python內(nèi)部關(guān)鍵詞沖突的一種約定,比如:

    tkinter.Toplevel(master, class_=‘ClassName’)
    
  • __double_leading_underscore:(雙下劃線開頭)當(dāng)這樣命名一個類的屬性時,調(diào)用它的時候名字會做矯正(在類FooBar中,__boo變成了_FooBar__boo;見下文)。

  • __double_leading_and_trailing_underscore__:(雙下劃線開頭,雙下劃線結(jié)尾)“magic”對象或者存在于用戶控制的命名空間內(nèi)的屬性,例如:__init__,__import__或者__file__。除了作為文檔之外,永遠(yuǎn)不要命這樣的名。

Prescriptive: Naming Conventions 約定俗成:命名約定

Names to Avoid 應(yīng)避免的名字

永遠(yuǎn)不要使用字母l(小寫的L),O(大寫的O),或者I(大寫的I)作為單字符變量名。
在有些字體里,這些字符無法和數(shù)字01區(qū)分,如果想用l,用L代替。

Package and Module Names 包名和模塊名

模塊應(yīng)該用簡短全小寫的名字,如果為了提升可讀性,下劃線也是可以用的。Python包名也應(yīng)該使用簡短全小寫的名字,但不建議用下劃線。
當(dāng)使用C或者C++編寫了一個依賴于提供高級(更面向?qū)ο螅┙涌诘腜ython模塊的擴展模塊,這個C/C++模塊需要一個下劃線前綴(例如:_socket

Class Names 類名

類名一般使用首字母大寫的約定。
在接口被文檔化并且主要被用于調(diào)用的情況下,可以使用函數(shù)的命名風(fēng)格代替。
注意,對于內(nèi)置的變量命名有一個單獨的約定:大部分內(nèi)置變量是單個單詞(或者兩個單詞連接在一起),首字母大寫的命名法只用于異常名或者內(nèi)部的常量。

Type Variable Names 類型變量名

PEP 484中引入的類型變量的名稱通常應(yīng)使用CapWords,而應(yīng)使用短名稱:T,AnyStr,Num。建議將后綴_co或_contra添加到用于分別聲明協(xié)變或反變行為的變量中:

from typing import TypeVar

VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)

Exception Names 異常名

因為異常一般都是類,所有類的命名方法在這里也適用。然而,你需要在異常名后面加上Error后綴(如果異常確實是一個錯誤)。

Global Variable Names 全局變量名

(我們希望這一類變量只在模塊內(nèi)部使用。)約定和函數(shù)命名規(guī)則一樣。
通過from M import *導(dǎo)入的模塊應(yīng)該使用all機制去防止內(nèi)部的接口對外暴露,或者使用在全局變量前加下劃線的方式(表明這些全局變量是模塊內(nèi)非公有)。

Function Names 函數(shù)名

函數(shù)名應(yīng)該小寫,如果想提高可讀性可以用下劃線分隔。
大小寫混合僅在為了兼容原來主要以大小寫混合風(fēng)格的情況下使用(比如 threading.py),保持向后兼容性。

Function and method arguments 函數(shù)和方法參數(shù)

始終要將 self作為實例方法的的第一個參數(shù)。
始終要將cls作為類靜態(tài)方法的第一個參數(shù)。
如果函數(shù)的參數(shù)名和已有的關(guān)鍵詞沖突,在最后加單一下劃線比縮寫或隨意拼寫更好。因此class_clss更好。(也許最好用同義詞來避免這種沖突)

Method Names and Instance Variables 方法名和實例變量

遵循這樣的函數(shù)命名規(guī)則:使用下劃線分隔小寫單詞以提高可讀性。
在非共有方法和實例變量前使用單下劃線。
通過雙下劃線前綴觸發(fā)Python的命名轉(zhuǎn)換規(guī)則來避免和子類的命名沖突。
Python通過類名對這些命名進(jìn)行轉(zhuǎn)換:如果類 Foo有一個叫 __a 的成員變量, 它無法通過 Foo.__a 訪問。(執(zhí)著的用戶可以通過 Foo._Foo__a 訪問。)一般來說,前綴雙下劃線用來避免類中的屬性命名與子類沖突的情況。
注意:關(guān)于__names的用法存在爭論(見下文)。

Constants 常量

常量通常定義在模塊級,通過下劃線分隔的全大寫字母命名。例如: MAX_OVERFLOWTOTAL。

Designing for inheritance 繼承的設(shè)計

始終要考慮到一個類的方法和實例變量(統(tǒng)稱:屬性)應(yīng)該是共有還是非共有。如果存在疑問,那就選非共有;因為將一個非共有變量轉(zhuǎn)為共有比反過來更容易。
公共屬性是那些與類無關(guān)的客戶使用的屬性,并承諾避免向后不兼容的更改。非共有屬性是那些不打算讓第三方使用的屬性;你不需要承諾非共有屬性不會被修改或被刪除。
我們不使用“私有(private)”這個說法,是因為在Python中目前還沒有真正的私有屬性(為了避免大量不必要的常規(guī)工作)。
另一種屬性作為子類API的一部分(在其他語言中通常被稱為“protected”)。有些類是專為繼承設(shè)計的,用來擴展或者修改類的一部分行為。當(dāng)設(shè)計這樣的類時,要謹(jǐn)慎決定哪些屬性時公開的,哪些是作為子類的API,哪些只能在基類中使用。
貫徹這樣的思想,一下是一些讓代碼Pythonic的準(zhǔn)則:

  • 公共屬性不應(yīng)該有前綴下劃線。

  • 如果公共屬性名和關(guān)鍵字沖突,在屬性名之后增加一個下劃線。這比縮寫和隨意拼寫好很多。(然而,盡管有這樣的規(guī)則,在作為參數(shù)或者變量時,cls是表示最好的選擇,特別是作為類方法的第一個參數(shù)。)
    注意1:參考之前的類方法參數(shù)命名建議

  • 對于單一的共有屬性數(shù)據(jù),最好直接對外暴露它的變量名,而不是通過負(fù)責(zé)的 存取器(accessor)/突變(mutator) 方法。請記住,如果你發(fā)現(xiàn)一個簡單的屬性需要成長為一個功能行為,那么Python為這種將來會出現(xiàn)的擴展提供了一個簡單的途徑。在這種情況下,使用屬性去隱藏屬性數(shù)據(jù)訪問背后的邏輯。
    注意1:屬性只在new-style類中起作用。
    注意2:盡管功能方法對于類似緩存的負(fù)面影響比較小,但還是要盡量避免。
    注意3:屬性標(biāo)記會讓調(diào)用者認(rèn)為開銷(相當(dāng)?shù)模┬。苊庥脤傩宰鲩_銷大的計算。

  • 如果你的類打算用來繼承的話,并且這個類里有不希望子類使用的屬性,就要考慮使用雙下劃線前綴并且沒有后綴下劃線的命名方式。這會調(diào)用Python的命名轉(zhuǎn)換算法,將類的名字加入到屬性名里。這樣做可以幫助避免在子類中不小心包含了相同的屬性名而產(chǎn)生的沖突。
    注意1:只有類名才會整合進(jìn)屬性名,如果子類的屬性名和類名和父類都相同,那么你還是會有命名沖突的問題。
    注意2:命名轉(zhuǎn)換會在某些場景使用起來不太方便,例如調(diào)試,__getattr__()。然而命名轉(zhuǎn)換的算法有很好的文檔說明并且很好操作。
    注意3:不是所有人都喜歡命名轉(zhuǎn)換。盡量避免意外的名字沖突和潛在的高級調(diào)用。

Public and internal interfaces 公共和內(nèi)部的接口

任何向后兼容保證只適用于公共接口,因此,用戶清晰地區(qū)分公共接口和內(nèi)部接口非常重要。
文檔化的接口被認(rèn)為是公開的,除非文檔明確聲明它們是臨時或內(nèi)部接口,不受通常的向后兼容性保證。所有未記錄的接口都應(yīng)該是內(nèi)部的。
為了更好地支持內(nèi)?。?code>introspection),模塊應(yīng)該使用__all__屬性顯式地在它們的公共API中聲明名稱。將__all__設(shè)置為空列表表示模塊沒有公共API。
即使通過__all__設(shè)置過,內(nèi)部接口(包,模塊,類,方法,屬性或其他名字)依然需要單個下劃線前綴。
如果一個命名空間(包,模塊,類)被認(rèn)為是內(nèi)部的,那么包含它的接口也應(yīng)該被認(rèn)為是內(nèi)部的。
導(dǎo)入的名稱應(yīng)該始終被視作是一個實現(xiàn)的細(xì)節(jié)。其他模塊必須不能間接訪問這樣的名稱,除非它是包含它的模塊中有明確的文檔說明的API,例如 os.path 或者是一個包里從子模塊公開函數(shù)接口的 __init__ 模塊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容