分析一套源代碼的代碼規範和風格並討論如何改進優化代碼python
1、結合工程實踐選題相關的一套源代碼,根據其編程語言或項目特色,分析其在源代碼目錄結構、文件名/類名/函數名/變量名等命名、接口定義規範和單元測試組織形式等方面的作法和特色git
我此次的工程實踐是圍繞密章檢測展開的,須要用到與目標檢測方面相關的知識,因而在github上找到了一套與此相關的代碼。這套代碼是基於python進行編程的,用到了pytorch框架和yolov3算法。github
一、源代碼目錄結構算法
從圖中能夠看出,源碼的目錄結構簡單清晰。編程
—assets/:存放原生資料文件,裏面存放的是一些圖片網絡
—config/:主要存放一些項目配置文件和命令文件框架
—data/:存放數據,包括訓練數據集和樣本圖片編程語言
—utils/:提供一些公共方法和輔助類方法的文件函數
—weights/:存放yolov3的配置文件和模型文件 單元測試
二、文件名/類名/函數名/變量名等命名
(1)文件名
detect.py:檢測目標
models.py:神經網絡模型
test.py:用來測試模型
train.py:用來訓練模型
README.md:簡要的描述該項目的信息,讓使用者快速瞭解這個項目
requirements.txt:經過requirements.txt來管理依賴庫
該項目中文件的命名仍是比較易讀的,根據命名就能夠大體瞭解這個文件主要是作什麼的,實現了什麼功能。同時經過README文件,使用者能夠知道在使用該項目時,應該作哪些準備以及如何正確使用項目。
(2)類名、函數名和變量名
以Darknet類爲例:這個類是nn.Module的子類,命名爲Darknet,接着進行一些初始化,網絡的前饋部分都是在foward的這個函數中完成的,pytorch會自動調用這個函數,首先,foward用來完成網絡從輸入到輸出的pipline,其次,將輸出的featuemap轉換爲更容易處理的形式。定義的forward函數如上所示,其包括三個參數,self,輸入x,和targets。關於yolo算法的類、函數和變量名的定義,其實已經漸漸造成了默認的標準,該項目的代碼也基本遵循了這些規範。
三、接口定義規範
該項目中並無明確地定義接口。實際上,python中無接口類型,定義接口只是一我的爲規定,在編程過程自我約束,在python中接口由抽象類和抽象方法去實現,接口是不能被實例化的,只能被別的類繼承去實現相應的功能。我的以爲接口在python中並無那麼重要,由於若是要繼承接口,須要把其中的每一個方法所有實現,不然會報編譯錯誤,還不如直接定義一個class,其中的方法實現所有爲pass,讓子類重寫這些函數。固然若是有強制要求,必須全部的實現類都必須按照接口中的定義寫的話,就必需要用接口。
廣義上來講,接口其實是定義一個規範、標準。不規範的代碼和開發習慣使工做中的大部分時間都在定位問題+改代碼,填堵遺留下來的坑,致使實際用於開發中的時間並很少,高質量、高效的代碼,能夠切實有效的提升工做效率,減小無謂的時間浪費。
四、單元測試組織形式
在目標檢測相關算法中,最重要的就是目標檢測的準確度,不只要對模型進行訓練,還要對訓練的結果進行準確度的測評。在該項目中,單獨使用一個test.py文件對模型訓練的結果進行測試。
2、列舉哪些作法符合代碼規範和風格通常要求
一、項目的目錄結構較好地遵循了項目開發的目錄規範,文件命名規範,一目瞭然。
二、代碼編排:
(1)縮進採用4個空格而非tab;
(2)類和top-level函數定義之間空兩行;類中的方法定義之間空一行
(3)每行不超過最大長度79
三、文檔編排:
一句僅import一個庫,採用from XX import XX引用庫時避免了命名衝突
四、註釋規範:
該項目中的註釋風格比較統一,基本都是使用"""來包圍註釋內容。
行註釋使用#。。。。
3、列舉哪些作法有悖於「代碼的簡潔、清晰、無歧義」的基本原則,及如何進一步優化改進
一、模塊、函數、類、方法的註釋過於簡潔,大部分函數基本沒有註釋,在讀代碼的時候比較費勁。
二、空行的做用就是隔離不一樣函數類等,使井井有條。在本項目的代碼中,不必的空行有點多
三、README.md文件只給了運行代碼的方式,安裝環境,啓動命令以及運行的效果進行說明,並無對項目的結構、項目中的代碼文件進行說明。
4、總結同類編程語言或項目在代碼規範和風格的通常要求
項目目錄規範:
經過規範化,可以更好的控制軟件結構,讓程序具備更高的可讀性。
參考的目錄結構:
個別說明:
README內容說明
1:軟件定位,軟件的基本功能
2:運行代碼的方式:安裝環境,啓動命令等。
3:簡要的使用說明。
4:代碼目錄結構說明,更詳細能夠說明軟件的基本原理
5:常見問題說明。
requirements.txt
文件格式是一行包含一個包依賴的說明,要求這個格式能被pip識別,使用方式:
pip install -r requirements.txt 來安裝全部依賴的包
以上各個目錄模塊如何動態導入,實現動態遷移。
Python代碼編寫規範:
一、代碼編排
(1)縮進。4個空格的縮進,不使用Tap,更不能混合使用Tap和空格。
(2)每行最大長度79,換行可使用反斜槓,最好使用圓括號。換行點要在操做符的後邊敲回車。
(3)類和top-level函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其餘地方儘可能不要再空行。
二、文檔編排
(1)模塊內容的順序:模塊說明和docstring—import—globals&constants—其餘定義。其中import部分,又按標準、三方和本身編寫順序依次排放,之間空一行。
(2)不要在一句import中多個庫,好比import os, sys不推薦。
(3)若是採用from XX import XX引用庫,能夠省略‘module.’,均可能出現命名衝突,這時就要採用import XX。
三、空格的使用
整體原則,避免沒必要要的空格。
(1)各類右括號前不要加空格。
(2)逗號、冒號、分號前不要加空格。
(3)函數的左括號前不要加空格。如Func(1)。
(4)序列的左括號前不要加空格。如list[2]。
(5)操做符左右各加一個空格,不要爲了對齊增長空格。
(6)函數默認參數使用的賦值符左右省略空格。
(7)不要將多句語句寫在同一行,儘管使用‘;’容許。
(8)if/for/while語句中,即便執行語句只有一句,也必須另起一行。
四、註釋
整體原則,錯誤的註釋不如沒有註釋。因此當一段代碼發生變化時,第一件事就是要修改註釋,註釋必須使用英文,最好是完整的句子,首字母大寫,句後要有結束符,結束符後跟兩個空格,開始下一句。若是是短語,能夠省略結束符。
(1)塊註釋,在一段代碼前增長的註釋。在‘#’後加一空格。段落之間以只有‘#’的行間隔。好比:
# Description : Module config.
#
# Input : None
#
# Output : None
(2)行註釋,在一句代碼後加註釋。好比:x = x + 1 # Increment x。可是這種方式儘可能少使用。
(3)避免無謂的註釋。
五、文檔描述
(1)爲全部的共有模塊、函數、類、方法寫docstrings;非共有的沒有必要,可是能夠寫註釋(在def的下一行)。
(2)若是docstring要換行,參考以下例子
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
六、命名規範
整體原則,新編代碼必須按下面命名風格進行,現有庫的編碼儘可能保持風格。
(1)儘可能單獨使用小寫字母‘l’,大寫字母‘O’等容易混淆的字母。
(2)模塊命名儘可能短小,使用所有小寫的方式,可使用下劃線。
(3)包命名儘可能短小,使用所有小寫的方式,不可使用下劃線。
(4)類的命名使用CapWords的方式,模塊內部使用的類採用_CapWords的方式。
(5)異常命名使用CapWords+Error後綴的方式。
(6)全局變量儘可能只在模塊內有效,相似C語言中的static。實現方法有兩種,一是__all__機制;二是前綴一個下劃線。
(7)函數命名使用所有小寫的方式,可使用下劃線。
(8)常量命名使用所有大寫的方式,可使用下劃線。
(9)類的屬性(方法和變量)命名使用所有小寫的方式,可使用下劃線。
(10)類的屬性有3種做用域public、non-public和subclass API,能夠理解成C++中的public、private、protected,non-public屬性前,前綴一條下劃線。
(11)類的屬性若與關鍵字名字衝突,後綴一下劃線,儘可能不要使用縮略等其餘方式。
(12)爲避免與子類屬性命名衝突,在類的一些屬性前,前綴兩條下劃線。好比:類Foo中聲明__a,訪問時,只能經過Foo._Foo__a,避免歧義。若是子類也叫Foo,那就無能爲力了。
(13)類的方法第一個參數必須是self,而靜態方法第一個參數必須是cls。