こんにちは!たっきん(Twitter)です!
今日はEclipseの開発支援機能である「リンター(コード解析)」と「フォーマッター(コード補完)」の紹介をしていきたいと思います。
この機能を使うとソースコード内のバグに繋がる恐れのある箇所を指摘してくれたり、事前に決められた規則(コーディング規約)に従い、ほぼ一瞬でコードを整形してくれたりします。
個人、チームでの開発を問わず、プログラミングする上でコードスタイルを気にかける必要がほぼなくなるため、爆速でキレイなコーディングを目指している方には必須の機能になります。
まだリンター、フォーマッターの機能を使ってない方は、これを機に設定方法や使い方をマスターしていきましょう!
なんでコードの整形が必要なの?
個人やチームでの開発を問わず、コードの解読やレビューなどで他人の書いたソースコードを読む機会は多いと思います。
そんなとき、以下のような<コードスタイル①>と<コードスタイル②>で書かれたコードを読むとなった場合、どちらのコードが読みやすいですか?
<コードスタイル①>
# ==============================================================================
# brief 閏年判定
#
# author たっきん
# ==============================================================================
def judge_leap_yaer():
while True:
try:
# 西暦の入力
print("西暦を入力してください = ")
year = int(input())
if year % 4 == 0:
if year % 100 == 0:
if year % 400 == 0:
print(" {0}年は閏年です。" .format(year))
else:
print(" {0}年は閏年ではありません。" .format(year))
else:
print(" {0}年は閏年です。" .format(year))
else:
print(" {0}年は閏年ではありません。".format(year))
except ValueError:
print("Error:数字以外が入力されました。")
if __name__ == '__main__':
judge_leap_yaer()
<コードスタイル②>
# ==============================================================================
# brief 閏年判定
#
# author たっきん
# ==============================================================================
def judge_leap_yaer():
while True:
try:
# 西暦の入力
print("西暦を入力してください = ")
year = int( input())
if year % 4 == 0:
if year % 100 == 0:
if year % 400 == 0:
print (" {0}年は閏年です。" .format(year))
else:
print ( " {0}年は閏年ではありません。" .format(year))
else:
print (" {0}年は閏年です。" .format(year))
else:
print ( " {0}年は閏年ではありません。" .format(year))
except ValueError:
print ("Error:数字以外が入力されました。")
if __name__ == '__main__':
judge_leap_yaer( )
恐らく、ほとんどの人が<コードスタイル①>のほうが読みやすいと感じるはずです。
プログラマはコードを書くのが主業務と思われがちですが、実際はコードを書くよりも読むことのほうに時間を費やされることも珍しくありません。
ましてや、自分で書いたコードだけでなく、他人が書いたコードを読む機会もそれなりに多いです。
そうした場合、読みにくいコードというのはプログラム構造の理解を妨げるだけでなく、モチベーションの低下にも繋がってきます。
そうならないためにも、事前にコーディング規則を定めて、誰がコードを書いても同一のスタイルを保つために、コード整形が必要になってきます。
規則正しくコードを書いたほうが、他人に読んでもらう場合も、後々自分で読み返す場合もストレスなく短時間でコードを理解することができるメリットがあります。
コードの自動解析&自動整形機能で楽しよう!
いくら「コーディング・スタイルを守らねば!!」と意識していてもミスは付きもの。
いちいちコーディング・スタイルを気にしながらコードを書いていたら、それだけでストレスが溜まってしまいますよね。
Eclipseには、そのような問題を解決する機能としてコード解析機能の「リンター」と、コード補完機能の「フォーマッター」が備わっています。
コード解析機能「リンター」
リンターは特定のコーディングパターン(コーディング規約)に違反している箇所や、構文エラーではないが潜在的に不具合となり得る個所を指摘してくれるツールの総称になります。
静的解析ツールと言われたりもします。
Eclipseのセットアップ直後はデフォルトで下記4つのリンターが使用できるようです。
- PyDevコード分析
- Flake8
- Mypy
- PyLint
フォーマッターと違い、リンターは指摘のみなので複数種類のリンターを有効にすることができます。
<リンター実施結果例>
PyDevコード分析
PyDevコード分析はpythonのプログラムエラー検出や未使用変数、未使用インポートなどを警告してくれます。
Eclipse導入時はデフォルトで有効になっています。
<PyDevコード分析で検出できるもの>
- 未定義の変数
- インポートからの未定義の変数
- 未使用の変数
- 未使用のインポート
- 未使用のワイルドカードインポート(import *)
- 非推奨シグネチャ
- 再定義されたインポート
- 解決できないインポート
- クラスメソッドで未宣言の”self”トークン
- インデント内でのタブとスペースの混在
- 間違ったインデント(スペースの数が不正)
Flake8
Flake8は下記3つのチェッカーを複合したツールになります。
- PyFlakes(コードのエラーをチェック)
- pycodestyle(PEP8に準拠しているかのチェック)
- Ned Batchelder’s McCabe script(循環的複雑度のチェック)
Pythonのリンターとしては比較的有名で、まずはこれを入れておけば包括的にコードチェックが行えると思います。
Eclipse導入時はデフォルトで無効になっているため、使用する場合は有効にする必要があります。
Mypy
Mypyは静的型チェッカーになります。
静的型付けのC言語とは違い、Pythonは動的型付けですが、Python 3.5より型ヒント(Type Hints)の仕組みが導入され、”静的型付けのような”言語として扱うことができるようになりました。
”静的型付けのような”とあえて書きましたが、型ヒントを用いることでC言語のように厳密に型が固定されるわけではありません。
動作自体は動的型付けとしての挙動となり、型ヒントはあくまでもコメントに近い位置付けであり、Mypyのような型チェッカーなどのツールで使用されることを想定しています。
よってMypyを使うか否かは好みでよいと思います。
動的型付けの最大のメリットはデータ型を気にしなくてよいためコーディングの自由度が高まることですが、型ヒントの導入はこの自由度を犠牲にすることになるからです。
Eclipse導入時はデフォルトで無効になっているため、使用する場合は有効にする必要があります。
PyLint
PyLintはFlake8は同等レベルの静的解析を行ってくれるツールになります。
Flake8と併せて導入しておきたいツールになります。
Eclipse導入時はデフォルトで無効になっているため、使用する場合は有効にする必要があります。
ちなみに、PyDevコード分析とPyLintの違いですが、PyLintが完全性を優先するのに対し、PyDevコード分析は誤検知を減らすため、少数かつ高速なチェックを優先します。
これはPyLintがPyDevコード分析よりも多くのエラーを検出することができることを意味しますが、実行速度と誤検知率が増加する可能性があります。
参考:What’s the differences from the PyDev code analysis to PyLint?
コード補完機能「フォーマッター」
フォーマッターは事前に決められた規則(コーディング規約)に従い、ほぼ一瞬でコードを整形してくれる機能になります。
リンターは指摘だけでしたが、フォーマッターは整形までしてくれます。
となるとリンターは不要なのでは?と思う方もいると思いますが、リンターの指摘内容によっては自動で整形できない箇所もあり、その場合は手動で修正する必要があります。
なので基本的には、まずフォーマッターで整形を行い、残ったリンターの指摘を手動で修正していく形で使い分けていくのが良いでしょう。
Eclipseのセットアップ直後はデフォルトで下記3つのフォーマッターが使用できるようです。
- PyDev.Formatter
- autopep8
- Black
フォーマッターはコード整形機能になるため、リンターと違って1種類のみしか有効にすることができません。
Eclipse導入時はPyDev.Formatterがデフォルトで有効になっています。
<フォーマッター実施結果例>
PyDev.Formatter
PyDev.FormatterはEclipse(PyDev)でデフォルトで設定されているフォーマッターになります。
カスタマイズ性はそこそこありますが、2018年を最後に更新されてないようです。
(フォーマッターのため、あまり更新する必要もなさそうですが・・・)
autopep8
autopep8はPEP8に準拠するようにコードをフォーマットします。
Black
「デフォルトの設定が全てだ」と謳っているくらいカスタマイズ性は低いです。
逆に言うならBlackを使っておけば誰がフォーマットしても同一規則に準拠したコードで整形できるというわけです。
最近割と人気のあるツールのようです。
Eclipseの設定手順
設定手順は「Eclipse 2022」バージョンを使って説明していきます。
バージョンによっては表示画面やメニューが多少異なっているかもしれませんが、基本的には同様の操作で設定できるはずです。
リンター
リンターは複数種類を同時に有効にすることができるため、今回はEclipseでデフォルトで使用できる下記4つのリンターを導入し、有効にしていきます。
- PyDevコード分析
- Flake8
- Mypy
- PyLint
まずはパッケージのインストールをしていきましょう。
PyDevコード分析だけはPyDevインストール時に同時にインストールされています。
Anacondaをインストールしている場合は、下記のコマンドでインストールできます。
$ conda install flake8
$ conda install mypy
$ conda install pylint
パッケージのインストールが完了したらEclipseを起動してメニューの「ウィンドウ」→「設定」を選択します。
設定ウィンドウが開いたら、左のペインから「PyDev」→「エディター」→「コード解析」を選択します。
PyDevコード分析はデフォルトで有効になっているため、「コード分析を行いますか?」にデフォルトでチェックが入ってるはずです。
チェックが入ってなければチェックを入れておきましょう。
Flake8
Flake8を有効にしたい場合は左ペインで「Flake8」を選択し、右ペインの「Flake8を使用する?」にチェックを入れ、「適用して閉じる」をクリックします。
Mypy
Mypyを有効にしたい場合は左ペインで「Mypy」を選択し、右ペインの「Mypyを使用する?」にチェックを入れ、「適用して閉じる」をクリックします。
PyLint
PyLintを有効にしたい場合は左ペインで「PyLint」を選択し、右ペインの「Pylintの使用」にチェックを入れ、「適用して閉じる」をクリックします。
指摘の重要度のカスタマイズ
各リンターは“指摘の重要度”をカスタマイズできる場合が多いです。
重要度は高い順から“エラー”、“警告”、“情報”となります。
“無視”を選択すると何も指摘されなくなります。
<PyDevコード分析のカスタマイズ画面>
<指摘の重要度の説明と表示例>
指摘の重要度 | 説明 |
---|---|
エラー | ツールの実行を妨げる重大なイベントを示します。 |
警告 | ツールの実行中に問題につながりかねない状況が発生した場合、 または結果がユーザーの期待するものとは異なる可能性がある場合を示します。 |
情報 | ツールの実行に関する情報です。 問題を示すために使用されることはありません。 |
指摘の重要度 | 表示例 |
---|---|
エラー | |
警告 | |
情報 |
フォーマッター
フォーマッターはコードを整形する機能になるので1種類しか有効にできません。
Eclipse導入時はPyDev.Formatterがデフォルトで有効になっていますが、他のフォーマッターを使いたい場合の切り替え方を説明していきます。
Eclipseの設定ウィンドウを開き、左のペインから「PyDev」→「エディター」→「コードスタイル」→「コード・フォーマッター」を選択します。
次に右ペインの「フォーマット・スタイル?」のドロップダウンリストから使用したいフォーマッターを選択します。
その後、「適用して閉じる」をクリックします。
これでフォーマッターの設定は完了です。
次は実際にフォーマッターでコード整形していきましょう。
例として下記のような整形前のコードを用意しました。
リンターのFlake8で5項目ほどエラー指摘を受けている状態です。
まずはエディター上で整形したい箇所を選択します。
基本的にはコード全体を整形することになるので「Ctrl+A」でコード全体を選択しましょう。
選択後は「Ctrl+Shift+F」で整形されます。
メニューの「ソース」→「コードのフォーマット」からでも実行できますが、実行頻度が高いのでショートカット・キーで実行するようにしたほうが楽です。
コードが整形されてリンターFlake8の指摘も全て解消されました。
フォーマッターの自動実行
ショートカット・キー「Ctrl+Shift+F」でフォマッターを実行できますが、ファイル保存時に自動で実行するように設定することもできます。
Eclipseの設定ウィンドウを開き、左のペインから「PyDev」→「エディター」→「保存アクション」を選択し、右のペインで「Auto-format editor contents before saving?」にチェックを入れ、「適用して閉じる」をクリックします。
フォーマッターで自動整形できない例
何かと便利なフォーマッターですが、リンターで検出された箇所全てをフォーマッターが修正してくれるわけではありません。
例えば例外処理。
以下のコード7行目を見てください。
try:
# 西暦の入力
print("西暦を入力してください = ")
year = int(input())
except: # PEP8違反箇所!中身のない例外処理を利用してはいけない。
print("Error:数字以外が入力されました。")
7行目で中身のない例外処理を書いていますが、これはPEP8の規約に違反します。
しかし中身は人が決めないといけないため、このような箇所はフォーマッターでは修正できません。
このような場合は人の手で修正することになります。
try:
# 西暦の入力
print("西暦を入力してください = ")
year = int(input())
except ValueError: # 例外処理の中身を定義。
print("Error:数字以外が入力されました。")
コメント