替代方案(推薦!)Python 開發:Ruff Linter、Formatter 介紹 + 設定教學

相關文章:確保 isort 正確排序本地模組:pyproject.toml 與 pre-commit 設定


最近發現,VS Code Python 擴充套件附帶的 isort 功能失效了!打開settings.json查看相關設定:

1
2
3
4
"python.sortImports.args": [
"--src=${workspaceFolder}",
"--line-length=100",
],

VS Code 會提示這樣的訊息:

This setting will be removed soon. Use isort.args instead.

果然該來的還是要來,在〈VS Code:試用從 Python extension 拆分的 Black、isort 套件〉中提過,微軟一直在積極拆分 Python 擴充套件功能,試圖為其「減肥」與解耦

而 linter 和 formatter 正是拆分的一大重心所在,前者目前已有 PylintFlake8,後者則有 Black,都是微軟官方出品。(yapf 表示:因為我來自 Google 就差別待遇?)

再參考 iThome 這篇〈VS Code Python擴充套件現在會預設安裝匯入項目排序擴充套件isort〉,顯然 VS Code 官方認為,isort 的正式獨立時機已到。

那就不等了,乖乖安裝 isort 擴充套件吧!


isort 簡介

github.com/PyCQA/isortgithub.com/PyCQA/isort

isort 其實就是一個 formatter,同時也是命令列工具,類似 yapf、Black,但它只負責和 import 有關的格式化,所以常常被忽略。

畢竟,import 順序,在絕大部分情況下,就只是美醜一致性的區別而已。

我屬於較在乎這些細節的人,法律的訓練讓我難以忍受事物沒有基本的條理。況且,在 PEP 8 中,已有對 import 的相關規範

尤其在團隊協作時,這樣的「一致性」更是需要確保。所以我仍然強烈建議:為專案的 import 進行合理排序——反正我是無法接受隨便排辣!🙈

剛開始寫 Python 時,我都是手動排序 import 以遵守 PEP 8 規範。這種方式不僅效率極低,也讓你不禁懷疑——這真的是人類該做的事嗎?

當然不是!所以我們有了 isort。

isort 三大排序亮點

isort 作為一個命令列工具,有著不少的參數可供使用,但我們對它的功能需求其實很簡單——就是妥善地幫我們排序 import,以符合 PEP 8(如下 1)。

此外,它還會幫你進行更細緻的排版(如下 2、3),讓偏執如我,感到非常舒服。😌

如果你還沒用過 isort,以下三個格式化亮點,足以讓你決定要不要用它:

  1. isort 會自動將 import 分為「內建」、「第三方」、「本地」套件等三大區塊,並依字母順序排列,同時為你在三個區塊之間空一行
    1. 區塊內會先排序import xxx,再列出from xxx import yyy
    2. 區塊間的分類與排序,屬於 PEP 8 範疇,其餘的排序,則是 isort 自訂的。
    3. 如果你違反了 PEP 8 的規範,isort 也會貼心地自動幫你修正。比如import docker, pytest,會被修正為import dockerimport pytest
  2. from x import a, b, c...等大量模組元件時,a、b、c 等模組也會依照名稱的首字母進行排序,令人十分舒爽!(單純的import則無此問題,因為 PEP 8 要求我們:每一行import只能導入一個項目
  3. from import內容超過設定「單行字元上限」時,會幫你自動添加括號,目的是為了優雅地換行(但邏輯上仍屬同一行)!相反地,在移除項目後,又符合單行上限時,則會自動取消括號,回復成單行。這功能真是太美妙了。😇

如果上述 3 點皆未讓你感到心動,那或許就真的不需要它了。

自動整合相同模組的 import

isort 還有一個我覺得很不錯的特性,就是「自動整合相同模組的 import」。

假設你有下列這兩行 import,其中一行是後來才加的,你未必有注意到兩者來自相同的模組(當導入的元件眾多,或相距較遠時,很可能會漏看):

1
2
3
from django.core.validators import FileExtensionValidator
...
from django.core.validators import MaxLengthValidator

但因為它們都是來自django.core.validators,所以 isort 會幫你整合成:

1
from django.core.validators import FileExtensionValidator, MaxLengthValidator

VS Code isort 套件簡介

如前所述,isort 是一個命令列工具,而 VS Code isort 套件,則是對 isort 進行封裝,以方便和 VS Code 整合使用。

換句話說,這套件的核心,仍然是 isort package。

既然如此,套件勢必得預裝「某個版本的 isort」。這意味著它的 isort 版本不是你決定,而是套件決定。

所幸這對我們來說,不算是個問題——套件通常採用當前最新版本。而且套件也允許你重新指定自己安裝的 isort 路徑。

使用 VS Code 套件版 isort 的最大優勢

為什麼我推薦使用這些 linter、formatter 的 VS Code 套件版本?而不是和以前一樣,將它們直接安裝到專案的 Python 虛擬環境中?

理由很簡單,因為這些套件可以在不同專案之間「共用」,所以你只需要安裝一個 VS Code 套件,就不必再各個專案的 Python 虛擬環境重複安裝。

如此不止節省空間,專案的環境也更加整潔。

2023/07/05補充:如同 Flake8、Black Formatter 擴充套件(都是微軟出的),當你的虛擬環境沒有安裝 isort 時,擴充套件會使用它預設的版本。如果虛擬環境有安裝 isort,擴充套件則會使用虛擬環境中的版本

The bundled isort is only used if there is no installed version of isort found in the selected python environment.

相關文章:VS Code:Python Flake8 與 Black Formatter 擴充套件快速上手

這些工具——無論是 linter、formatter——它們與實際產品專案沒有直接相關,對版本也沒那麼敏感,可以隨時升級而不影響專案的穩定。

所以,它們「特別適合」獨立出來共享

但話說回來,如果是團隊協作,那這些工具的版本還是要盡可能統一才好。避免不同的開發者使用不同版本,造成格式不一致的問題。


VS Code isort 套件設定

安裝套件後,原則上你無須設定就可以使用,不過還是值得了解一點細節,以方便進行客製化微調,比如最常見的——變更單行字元上限。

關於 isort 套件在 VS Code settings.json中的設定事項,套件首頁已有介紹。在此特別提其中的兩個,以及一個「存檔時自動格式化」的設定。

一、isort.args

不用說,這是最重要的設定項目。

如同 Flake8、yapf,args的設定本質上就是 isort 的命令列參數(引數),可以改變格式化的行為。

其中最常見的需求,就是「更變單行字元上限」,以免它和你的 linter、formatter 不一致。"--src=${workspaceFolder}"則是修正 isort 套件在判斷專案本地路徑時可能發生的錯誤,詳細內容可參考此 issue

1
2
3
4
"isort.args": [
"--src=${workspaceFolder}",
"--line-length=100",
],

二、isort.check

1
"isort.check": true,

預設為false,其作用在於——是否讓 isort 像 linter 那樣,在排序不符合規範時給出提醒

這提醒目前只會出現在第一行這提醒目前只會出現在第一行

isort 作為一個格式化工具,無論是否提醒,它最終都會將這些不合規之處加以格式化——只要你沒忘記——所以預設為false。我個人則偏好把它打開。

三、存檔時自動格式化

呼叫 isort 執行格式化,除了使用右鍵選單,另一種方式就是設定快捷鍵。但這兩種方法都不盡理想——很容易忘記

最好的做法還是設定「存檔時自動格式化」,這部分在〈VS Code:試用從 Python extension 拆分的 Black、isort 套件〉已介紹過,設定如下:

1
2
3
4
5
6
"[python]": {
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
...
},

把適合機器做的事,慎重地交付給機器完成,無疑是個良好的習慣。


結語

isort 在 Python 開發中的地位,顯然不如 Flake8、yapf 等工具,但對於重視程式碼品質的我們,它與上述二者的重要性,並沒有本質上的區別。

換句話說,對於重視程式寫作規範,意在貫徹 Clean Code 精神的開發者而言,它不是一種選擇,而是一種必然。