Python coding style 1: 基本概念 & linter

Coding style 大部分人都知道很重要,但很多人都不研究或實行。這其實是蠻怪的一件事,我認識的人很多對 Python coding style 的認知都很低。但我覺得很多時候是不知道從哪裡著手,也不知道要做到什麼程度,於是我就想來把最近幾年自學的經驗分享給大家。

先來點基本的~什麼是 coding style?

Coding style 最普遍的定義就是寫程式時遵守的規範和依循的邏輯,其實管到的東西非常多。小從哪裡要空格,哪裡要換行,變數命名原則。大到寫某個東西的時候要用哪個 function,要用哪種方式寫等等的。

為什麼需要 coding style?

一般常見的目的就是為了提昇可讀性減少錯誤發生的機率,甚至是提昇效能。上面講的大概就是大家普遍認知的東西,但有些東西其實沒有親身體驗很難了解,特別是前兩項,在多人合作的時候會完全提升到另一個境界。所以我在這邊特別細講幾個觀察:

  1. 編輯環境的適應性:好的 coding style 應該要在各個編輯器都能很一致的良好呈現。

– 這也是為什麼目前大部分人都使用空格,而不使用 tab
每行字數限制可以讓大家在切割左右視窗的時候 code 不會超出邊界,也不會因為 line wrap 讓大家看到的不一樣。
2. 不是只要寫得漂亮,還要統一:其實很多 coding style 規範不一定有好的理由,最關鍵的是在統一
– 相信大家都有一個經驗,就是讀別人的 code 的時候,不管寫得好不好,都會感覺很不舒服,不是很好懂,心情很差,其中很大的原因是在 coding style。
– 當大家使用同樣的規範嚴謹的寫程式時,解讀一段 code 所需的腦內 “parser” 複雜度就會低上許多,看到別人的 code 的時候就會像看到自己的,有一種親切感。
3. 表達隱含意義:Coding style 可以讓程式表達出超越程式邏輯的意義。
– 其實我們在寫程式的時候,兩個不同概念,但是邏輯完全一樣的東西,我們有可能會寫成不同的樣子。如果大家遵循相同的方法,就可以讓程式在有這些提示下更容易地被解讀。反之,在閱讀別人的 code 的時候就會失去這些引導,容易感到困惑。
– 最好解釋的例子是雙引號和單引號議題,Python 的單雙引號其實功能上完全一樣,不知道有沒有人想過要怎麼使用?在這篇 stack overflow 問題中,就有人提出單引號代表 symbol,雙引號代表自然語言,這樣就讓這個程式多了一層意義。

所有寫 Python 的人都應該知道的 PEP 8

Python Enhancement Proposal (PEP) 裡面有許多 Python 本體開發相關的文件,像是某個新功能的開發理念,某個功能改變的說明等等的。其中 PEP 8 在 2001 年就被提出,當初是用來規範 Python 本體 library 的 coding style,後來漸漸被幾乎所有 Python package 採用。比較早開始寫 Python 的人可能會發現,不少 package 的 API 原本都是 camelCase,但某個時間過後幾乎全部都變成 snake_case 了。現在,幾乎所有 Python 開發者都會遵守 PEP 8 大部分的規範,這也是 Python package source code 大部分可讀性都很高的其中一個原因(當然,語言本身設計良好也是主因)。

所以到底要怎麼開始改善 coding style?

你以為我會說先去把 PEP 8 讀完或是買哪本書嗎?那你就錯了!讀 PEP 8 要花的時間太多,而且親身經歷之前可能都不太能理解,讀起來會枯燥乏味。這種事就交給我吧,我下一篇會挑一些 PEP 8 的重點來講。所以到底要從哪開始?當然是他X的打開你的 EditorConfig 和 linter!!抱歉有點激動,這是我每次跟新夥伴合作,收到第一個 PR 時的 OS。

EditorConfig

EditorConfig 是一個幾乎所有編輯器都會有的 plugin,它能讓開發者統一一些編輯器的設定。只要在 project 根目錄放一個 .editorconfig 的設定檔,開啟 EditorConfig plugin 後,編輯器就會自動設定好。因為設定上非常容易,我就不多說了,直接來個設定範例。在 python 下常用的設定:

root = true

[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2

[*.py]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

[*.rst]
indent_size = 3

藉由大家統一這個設定檔,可以讓所有開發者都在看似一樣的編輯器環境下工作。相信大家從字面上就可以看出來這個在設定什麼了XD 詳細解釋就請大家自行去它網站上看,或是直接動手玩囉。另外,在我寫完這篇文章之後,剛好看到一個不錯的 youtuber 發了介紹 EditorConfig 的影片,也可以參考看看。

這邊有個小插曲,我幾個禮拜前剛用 VS Code,結果他的 EditorConfig extension 居然是壞的,完全沒有作用。還好缺少這功能短時間還不會想死。我最近使用 VS Code 的感想就是他有一堆死不了的 bug,但就是大部分功能都還不錯。其實使用編輯器最容易令人挫折的是,它就是少了一個必要的功能,而 VS Code 在這裡做得不錯,大部分必須的功能它都有。而且雖然我一開使用的時候 EditorConfig 是壞掉的,但在我回報 bug 細節之後在幾個小時內就被修好了。

Linter

這個就複雜了,linter 可以幫你檢查你的 code,告訴你哪裡寫的不好,應該要改進。其實從解除 linter 的警告中,就可以快速的學習 coding style 了。而前面提到的 PEP 8 也是幾乎所有 linter 都必備支援的檢查,所以從和 linter 互動的過程中也可以快速的學到 PEP 8 的一些規範。
Python 最常被使用的 linter 大概就是 pylintflake8,兩個都是以 python package 的形式存在,也提供 command line tool。我通常也不會對他們做太大的客製化,以我的觀點來看,他們的差別是:

  • pylint 會做非常複雜的分析,例如會檢查 import 會不會失敗等等的跨檔案的檢查,因此速度非常慢,通常只要開發幾個禮拜的程式,對一個檔案做一次 pylint,就會花 5~10 秒,甚至更長的時間
  • flake8 只做單檔檢查,速度非常快,幾乎都是一瞬間

使用上我覺得,如果你用的編輯器不支援 pylint 的 on-the-fly linting,那速度會非常慢,建議還是用 flake8。但在做 Continuous Integration (CI) 的時候還是建議用 pylint 做比較深度的檢查。

這兩個套件也都有支援設定檔,他們也都有一些預設的位置可以放設定,詳情就請看他們的 documentation 囉~

常見的編輯器,例如 Vim, Sublime Text, Atom, PyCharm, VS Code 都有不錯的 linter plugin 可以使用,有些有支援 pylint 或 flake8,有些是支援其他的 linter。我挑幾個我用過的來介紹:

  • Sublime Text
  • Pylinter, Anaconda, Python Flake8 Lint
  • Atom
  • 有支援 pylint, flake8 的 plugin,但我使用上遇到超多挫折,於是就放棄 Atom 了。
  • PyCharm
  • 非常囂張的不支援這些 linter 套件,完全用自己那套,所以團隊合作上我不太建議使用 PyCharm,因為不容易做出統一的設定。
  • VS Code
  • 一個 Python extension 全包。

VS Code

由於最近 VS Code 正夯,而且我使用起來也覺得蠻喜歡的,所以我就來特別教一下怎麼設定 VS Code XD
我只講解 by-project 的設定方式,因為大部分時候 linter 是要跟著 project 做設定的,而且全域設定當然是更簡單,不需要多作說明。

  1. 首先你要有 VS Code,然後裝好 Python extension,相信這不難
  2. 再來開啟一個 project,然後用 ctrl+, 開啟設定,然後點選右上角的 WORKSPACE SETTINGS
    Screenshot_20170502_235319
  3. 在右邊貼入和修改以下設定
{
"python.pythonPath": "${env.HOME}/.pyenv/versions/test/bin/python",
"python.linting.flake8Path": "${env.HOME}/.pyenv/versions/test/bin/flake8",
"python.linting.flake8Enabled": true,
"python.linting.pylintEnabled": false
}

這個是我其中一個常用的設定,我會關閉 pylint (預設是開啟),並且打開 flake8,然後還要告訴它 python 和 flake8 binary 所在的路徑。因為我們通常每個 project 會用不同的 virtual environment,所以套件和 python binary 的位置會比較特殊,沒辦法直接用系統預設的路徑中找到。

這邊的例子是用 pyenv 來建立 virutalenv 時的狀況。如果不知道你的路徑是什麼,可以用 which pythonwhich flake8 來找到,如果你是用 pyenv,那就要使用
pyenv which pythonpyenv which flake8。另外,在 VS Code 的 Python extension 中,它提供了一些變數可以在路徑中使用,例如 ${env.XXXX} 可以從環境變數中拿到值,我這邊用的 ${env.HOME} 意思就是環境變數中的家目錄(在我寫出這篇文章的一天後它就支援直接用 ~/ 來表示家目錄了QQ 真的更新很快),就等同你在 shell 上面打 echo $HOMOE 會拿到的東西。另外也有 ${workspaceRoot} 這個變數,它代表你現在這個 project 的根目錄。

這些都設定好之後,只要你寫 python code,做一次儲存後,就會自動進行檢查,把有問題的地方劃線。滑鼠移上去就可以看到問題是什麼,也可以用 ctrl+shift+m 打開問題列表,或是用 F8shift+F8 搜尋上一個或下一個有問題的地方。

接下來還能做什麼?

熟悉了 linter 之後,接下來的每個 project 都應該在最一開始就把設定檔通通都放好,然後跟團隊溝通好使用方法,於是最基本的 coding style 規範就有囉~如果是要求更高的 project,最好也要在 CI 上做檢查,避免髒 code 進來。

當然,只有這樣是不夠的,再下一部就是研讀 PEP 8 中的規範了。其實我以前都沒有仔細完整讀完 PEP 8 過,最近想說來讀一下,順便記個筆記,下一篇應該就會是這個筆記,主要是會把一些令我驚奇,或是常看到會有人犯錯的地方寫下來,做一個導讀。

Advertisements

4 thoughts on “Python coding style 1: 基本概念 & linter

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: