程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python 編程規范和軟件開發目錄規范的重要性

編輯:Python

文章目錄

  • 1 編程規范的重要性
    • 1.1 注釋
      • Python 中的特殊注釋
    • 1.2 規范命名變量:
      • 1.2.1 變量定義規則:
      • 1.2.2 變量規范命名注意事項:
      • 1.2.3 總體命名規則:
    • 1.3 排版問題
      • 1.3.1 代碼排版:
      • 1.3.2 文檔排版:
      • 1.3.3 空格的使用:
    • 1.4 其他
  • 2. 軟件開發目錄規范的重要性
    • 2.1 為什麼要設計好目錄結構?
    • 2.2 目錄組織方式
    • 2.3 README項目說明文件
      • 2.3.1 為什麼要寫README文件?
      • 2.3.2 完整的README包含的內容
      • 2.3.3 一個簡單的范本
      • 2.3.4 規范的README文件怎麼寫?
    • 2.4 關於requirements.txt和setup.py
      • 2.4.1 setup.py
      • 2.4.2 requirements.txt
        • 2.4.2.1 生成方式
        • 2.4.2.2 載入方式
    • 2.5 關於配置文件的使用方法

1 編程規范的重要性

1.1 注釋

每條注釋以井號(#)開始,一直到該行末尾結束,一直到該行末尾結束。我們可以在注釋中放任何東西,因為Python 會完全無視他們的存在。這裡給出以後幾條規則:
(1) 假設讀者的Python 水平和你一樣(比如說,不要去解釋 “ 什麼是字符串 ” , 也不要去解釋 “ 什麼是賦值語句 ”)
(2) 不要去注釋毫無意義的事情。
(3) 很多程序員會在代碼上寫上一些以 **“ TODO ” 或者 “ FIXME ”**開始的注釋,目的就是為了提醒他們回來編寫或清理一些未完成的一些問題。
(4) 如果你在編寫某段程序的時候需要使勁思考的話,應該編寫注釋,以後別人不會在這個地方絞盡腦汁。尤其要注意的是,如果你在開發程序的時候或者函數編寫的時候使用要點來描述,盡量寫的細致一點,在開發工作完成之後,還應該將原來的要點全部保留下來直接做解釋。
(5) 同樣,如果某個bug很難查明,或者其修改方案比較復雜,那麼你就應該編寫一條注釋對其進行解釋。如果不這麼做,那麼今後其他復雜該部分的代碼的程序員就會可能認定他們沒有必要這麼復雜並將其改為原來的樣子,從而將你的心血付諸東流。
(6) 如果需要大量的注釋才能解釋清楚某段代碼的作用,那麼就應該對這些代碼進行整理,比如,如果需要分別對一個函數的15個列表進行解釋,那麼就應該將該函數拆分成更小的代碼塊,每隔分別只處理較小的幾個列表。
(7) 過時的注釋還不如沒有注釋,因此修改某段代碼後,一定要檢查相關注釋,並對其做出適當的修改以保證其仍然能夠准確描述代碼的功能。
(8) 注釋不是越多越好,弄得整篇代碼都是注釋,卻很少看到代碼,這樣就曲解了注釋的意思了。

Python 中的特殊注釋

比如:Python有一行聲明python編碼格式的單行注釋。這行注釋指定文件為 utf-8 編碼。這行特殊注釋只能放在文件的第一行或者開頭.

#_*_coding:utf-8_*_

還有一種是說明腳本語言是python的,是要用/usr/bin下面的程序(工具)python,這個解釋器,來解釋python腳本,來運行python腳本的。

#!/usr/bin/python

1.2 規范命名變量:

1.2.1 變量定義規則:

(1) 變量名只能是字母,數字或者下劃線的任意組合
(2) 變量名的第一個字符不能是數字
(3) 關鍵字不能生成變量名

1.2.2 變量規范命名注意事項:

(1) 變量名不能過長
(2) 變量名詞不達意思
(3) 變量名為中文,拼音

1.2.3 總體命名規則:

(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。

1.3 排版問題

1.3.1 代碼排版:

(1) 縮進。4個空格的縮進(編輯器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。
(2) 每行最大長度79,換行可以使用反斜槓,最好使用圓括號。換行點要在操作符的後邊敲回車。
(3) 類和top-level函數定義之間空兩行;類中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方盡量不要再空行。

1.3.2 文檔排版:

(1) 模塊內容的順序:模塊說明和docstring—import—globals&constants—其他定義。其中import部分,又按標准、三方和自己編寫順序依次排放,之間空一行。
(2) 不要在一句import中多個庫,比如import os, sys不推薦。
(3) 如果采用from XX import XX引用庫,可以省略‘module.’,都是可能出現命名沖突,這時就要采用import XX。

1.3.3 空格的使用:

總體原則,避免不必要的空格
(1) 各種右括號前不要加空格。
(2) 逗號、冒號、分號前不要加空格。
(3)函數的左括號前不要加空格。如Func(1)。
(4) 序列的左括號前不要加空格。如list[2]。
(5) 操作符左右各加一個空格,不要為了對齊增加空格。
(6) 函數默認參數使用的賦值符左右省略空格。
(7) 不要將多句語句寫在同一行,盡管使用‘;’允許。
(8) if/for/while語句中,即使執行語句只有一句,也必須另起一行。

1.4 其他

(1) 編碼中考慮到其他python實現的效率等問題,比如運算符‘+’在CPython(Python)中效率很高,都是Jython中卻非常低,所以應該采用.join()的方式。
(2) 盡可能使用‘is’‘is not’取代‘==’,比如if x is not None 要優於if x。
(3) 使用基於類的異常,每個模塊或包都有自己的異常類,此異常類繼承自Exception。
(4) 異常中不要使用裸露的except,except後跟具體的exceptions。
(5) 異常中try的代碼盡可能少。比如:

try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
***優於***
try:
# Too broad!
return handle_value(collection[key])
except KeyError:
# Will also catch KeyError raised by handle_value()
return key_not_found(key)

(6) 使用startswith() and endswith()代替切片進行序列前綴或後綴的檢查。比如:

if foo.startswith('bar'):
***優於***
if foo[:3] == 'bar':

(7) 使用isinstance()比較對象的類型。比如

if isinstance(obj, int):
***優於***
if type(obj) is type(1):

(8) 判斷序列空或不空,有如下規則

if not seq:
if seq:
***優於***
if len(seq)
if not len(seq)

(9) 字符串不要以空格收尾。
(10) 二進制數據判斷使用 if boolvalue的方式

2. 軟件開發目錄規范的重要性

2.1 為什麼要設計好目錄結構?

我們設計一個層次清晰的目錄結構,要達到以下兩點:
① 可讀性高: 不熟悉這個項目的代碼的人,一眼就能看懂目錄結構,知道程序啟動腳本是哪個,測試目錄在哪兒,配置文件在哪兒等等。從而非常快速的了解這個項目。
② 可維護性高: 定義好組織規則後,維護者就能很明確地知道,新增的哪個文件和代碼應該放在什麼目錄之下。這個好處是,隨著時間的推移,代碼/配置的規模增加,項目結構不會混亂,仍然能夠組織良好。

2.2 目錄組織方式

假設你的項目名為foo, 我比較建議的最方便快捷目錄結構這樣就足夠了:

Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- init.py
| | |-- test_main.py
| |
| |-- init.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

其中:
bin/: 存放項目的一些可執行文件,當然你可以起名script/之類的也行。
foo/: 存放項目的所有源代碼。①源代碼中的所有模塊、包都應該放在此目錄。不要置於頂層目錄。② 其子目錄tests/存放單元測試代碼; ③ 程序的入口最好命名為main.py。
docs/: 存放一些文檔。
setup.py: 安裝、部署、打包的腳本。
requirements.txt: 存放軟件依賴的外部Python包列表。
README: 項目說明文件。
除此之外,有一些方案給出了更加多的內容。比如LICENSE.txt,ChangeLog.txt文件等,我沒有列在這裡,因為這些東西主要是項目開源的時候需要用到。

2.3 README項目說明文件

2.3.1 為什麼要寫README文件?

這個文件的目的是能簡要描述該項目的信息,讓讀者快速了解這個項目。

2.3.2 完整的README包含的內容

(1) 它需要說明以下幾個事項:

軟件定位,軟件的基本功能。
運行代碼的方法: 安裝環境、啟動命令等。
簡要的使用說明。
代碼目錄結構說明,更詳細點可以說明軟件的基本原理。
常見問題說明。

二,它包括了一下內容:

項目和所有子模塊和庫的名稱(對於新用戶,有時不同命名會導致混亂)
對所有項目,和所有子模塊和庫的描述
如何使用 5-line code(如果是一個庫)
版權和許可信息(或閱讀許可證)
抓取文檔指令
安裝、配置和運行程序的指導
抓取最新代碼和構建它們的說明(或快速概述和「閱讀 Install」)
作者列表或「Read AUTHORS」
提交bug,功能要求,提交補丁,加入郵件列表,得到通知,或加入用戶或開發開發區群的介紹
其他聯系信息(電子郵件地址,網站,公司名稱,地址等)
一個簡短的歷史記錄(更改,替換或者其他)
法律聲明

2.3.3 一個簡單的范本

當然,我們前期寫的話,不必要那麼麻煩,就寫幾個簡單的必要的東西,比如法律聲明啊,聯系記錄啊等等,就不必要寫。

###########環境依賴 node v0.10.28+ redIs ~

###########部署步驟

  1. 添加系統環境變量
    export $PORTAL_VERSION=“production” // production, test, dev

  2. npm install //安裝node運行環境

  3. gulp build //前端編譯

  4. 啟動兩個配置(已forever為例)
    eg: forever start app-service.js
    forever start logger-service.js

###########目錄結構描述 ├── Readme.md // help ├── app // 應用 ├── config // 配置 │ ├── default.json │
├── dev.json // 開發環境 │ ├── experiment.json //
實驗 │ ├── index.js // 配置控制 │ ├── local.json
// 本地 │ ├── production.json // 生產環境 │ └── test.json
// 測試環境 ├── data ├── doc // 文檔 ├── environment
├── gulpfile.js ├── locales ├── logger-service.js // 啟動日志配置
├── node_modules ├── package.json ├── app-service.js //
啟動應用配置 ├── static // web靜態資源加載 │ └── initjson │
└── config.js // 提供給前端的配置 ├── test ├── test-service.js └──
tools

###########V1.0.0 版本內容更新

  1. 新功能 aaaaaaaaa
  2. 新功能 bbbbbbbbb
  3. 新功能 ccccccccc
  4. 新功能 ddddddddd

2.3.4 規范的README文件怎麼寫?

對於常用windows的同學們,怎麼寫README呢?
需要使用MarkDown

這個網站可以直接編寫MarkDown語言
Markdown官方教程

2.4 關於requirements.txt和setup.py

2.4.1 setup.py

一般來說,用setup.py來管理代碼的打包、安裝、部署問題。業界標准的寫法是用Python流行的打包工具setuptools來管理這些事情。這種方式普遍應用於開源項目中。不過這裡的核心思想不是用標准化的工具來解決這些問題,而是說,一個項目一定要有一個安裝部署工具,能快速便捷的在一台新機器上將環境裝好、代碼部署好和將程序運行起來。

安裝環境、部署代碼、運行程序這個過程全是手動完成,遇到的問題:
①安裝環境時經常忘了最近又添加了一個新的Python包,結果一到線上運行,程序就出錯了。
②Python包的版本依賴問題,有時候我們程序中使用的是一個版本的Python包,但是官方的已經是最新的包了,通過手動安裝就可能裝錯了。
③如果依賴的包很多的話,一個一個安裝這些依賴是很費時的事情。
④新同學開始寫項目的時候,將程序跑起來非常麻煩,因為可能經常忘了要怎麼安裝各種依賴。
setup.py可以將這些事情自動化起來,提高效率、減少出錯的概率。"復雜的東西自動化,能自動化的東西一定要自動化。"是一個非常好的習慣。

一個例子:

from setuptools import setup
# Metadata goes in setup.cfg. These are here for GitHub's dependency graph.
setup(
name="Flask",
install_requires=[
"Werkzeug >= 2.0",
"Jinja2 >= 3.0",
"itsdangerous >= 2.0",
"click >= 8.0",
"importlib-metadata >= 3.6.0; python_version < '3.10'",
],
extras_require={

"async": ["asgiref >= 3.2"],
"dotenv": ["python-dotenv"],
},
)

當然,簡單點自己寫個安裝腳本(deploy.sh)替代setup.py也未嘗不可。

2.4.2 requirements.txt

這個文件存在的目的是:
①方便開發者維護軟件的包依賴。將開發過程中新增的包添加進這個列表中,避免在 setup.py 安裝依賴時漏掉軟件包。
②方便讀者明確項目使用了哪些Python包。

這個文件的格式是每一行包含一個包依賴的說明,通常是flask>=0.10這種格式,要求是這個格式能被pip識別,這樣就可以簡單的通過 pip install -r requirements.txt來把所有Python包依賴都裝好了。

2.4.2.1 生成方式

(1) pip freeze > requirements.txt
這種方式是會在當前路徑下生成一個requirements.txt文件,該文件中則會記錄當前python環境下所以擁有的所有包,以及包的版本。可以看作把pip list這個命令展現的所有東西記錄下啦。這種方式速度很快,但是requirements.txt文件包含的包是當前環境所有的包,如果你當前項目沒有用到的包也會被包括下來。
(2) pipreqs 目錄路徑
這種方式需要先通過pip install 安裝pipreqs模塊。
pip install pipreqs
定位到你所在項目的根目錄下,執行
pipreqs ./ --encoding=utf8
這裡加了–encoding=utf8是為了避免亂碼。這樣也會在當前目錄下生成requirements.txt文件,不過這個文件中包含的包版本就是當前項目中所用到的所有包的版本信息了。

2.4.2.2 載入方式

我們從github上克隆了某個項目,我們可以根據它的requirements.txt配置環境,推薦采用conda新建一個環境之後再使用以下命令。
pip install -r requirements.txt

2.5 關於配置文件的使用方法

注意,在上面的目錄結構中,沒有將conf.py放在源碼目錄下,而是放在docs/目錄下
很多項目對配置文件的使用做法是:
配置文件寫在一個或多個python文件中,比如此處的conf.py。
項目中哪個模塊用到這個配置文件就直接通過import conf這種形式來在代碼中使用配置。
這種做法我不太贊同:
這讓單元測試變得困難(因為模塊內部依賴了外部配置)
另一方面配置文件作為用戶控制程序的接口,應當可以由用戶自由指定該文件的路徑。
程序組件可復用性太差,因為這種貫穿所有模塊的代碼硬編碼方式,使得大部分模塊都依賴conf.py這個文件。
所以,我認為配置的使用,更好的方式是,
模塊的配置都是可以靈活配置的,不受外部配置文件的影響。
程序的配置也是可以靈活控制的。
能夠佐證這個思想的是,用過nginx和mysql的同學都知道,nginx、mysql這些程序都可以自由的指定用戶配置。
所以,不應當在代碼中直接import conf來使用配置文件。上面目錄結構中的conf.py,是給出的一個配置樣例,不是在寫死在程序中直接引用的配置文件。可以通過給main.py啟動參數指定配置路徑的方式來讓程序讀取配置內容。當然,這裡的conf.py你可以換個類似的名字,比如settings.py。或者你也可以使用其他格式的內容來編寫配置文件,比如settings.yaml之類的。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved