Make組ブログ

Python、Webサービスや製品開発、ライブラリー開発についてhirokikyが書きます

もうPythonの細かい書き方で議論しない。blackで自動フォーマットしよう

  • 「ここで改行するほうがキレイで良いと思います」
  • 『いや、私はこちらのほうがキレイ良いと思います』

コードレビューでこういう議論をしたことはありませんか? 大切なことだとは思いますが、生産性にはあまり直結しません。議論を避けるために書き方を決めるほうが良いでしょう (個々の問題について逐次議論するのがエネルギーを無駄にしてしまいます。一度決めて、再利用するようにしたいものです)。

今日はそのために使える black というツールを紹介します (「私はflake8を使ってるから結構です」と思われるかもしれませんが、少し違う話なので読んでみてください)。

blackを使おう

Pythonのコードを自動でフォーマットしてくれる black を紹介します。

github.com

blackはPythonのコードフォーマッターで、自動的にPythonプログラムの書き方を修正してくれます。 PEP8 というPythonのコードスタイルにも準拠していますので安心です。

Python向けの自動フォーマッターはいくつかありますが、他のフォーマッターとの違いは何でしょうか?一言で言うと、blackはより制限が強いということです。

blackの特徴

Pythonの自動フォーマッターといえば autopep8yapf などありますが、blackはより制限が強く、自由に設定ができないのが特徴です。

PEP8では触れられていない、改行の仕方や、シングルクォートとダブルクォートの統一、末尾カンマの統一、余計な丸括弧の削除、数値リテラルの書き方統一などをしてくれます。 私の捉え方としては、blackは「自動フォーマッター」というよりも「制限のきついPEP8」です

設定できることはせいぜいファイルの幅(文字数)や除外するディレクトリーの設定くらいでしょうか。 開発プロジェクトごとの違いや好みを反映することはほぼできません 。 「うちのプロジェクトはルールで、こう改行するように決めている」というのであれば、改宗するか、諦めるしかありません。 改行位置とかも自動で揃えられるので「ここの論理行はここで改行するのが好き」とかそういうのは無理です。

  • PEP8に自動で従ってほしい
  • PEP8で触れられてない以上のルールを設定したい
  • どこで改行するか議論したくない
    • \ で改行するか
    • () で改行するか
    • () のどこで改行するのか
  • シングルクォートを使うのか、ダブルクォートを使うのかで議論したくない
  • 「プロジェクトごとに色々設定」できないほうが楽で良い

私個人としてはこの「設定させない」というのは良いと思っています。

ただ「シングルクォートをダブルクォートに統一する」などのblackのルールは正直好みに合いません(私には『シンボル』的な文字列ならシングルクォートを、『文字列』的な文字列ならダブルクォートを使うというマイルールがありまして、そういった美的センスも大切だとは思いますがmuble mumble...)。

誰がblackを使っているの?

ココ最近、私の仕事での開発環境を整備していて、black をプロジェクトに導入しました。 Used by を見ると他に使っている人のコメントが読めます。

また、Djangoソースコード開発ではblackを使うというプロポーザルがアクセプトされています。

github.com

ただ、blackはまだ公式には 「まだベータだよ」 と言っていますので、性急に捉える必要はないでしょう。

https://github.com/python/black#note-this-is-a-beta-product

blackを使おう

blackは単なるコマンドなので、インストールして使うだけです。

pip install black
black <target>

blackを設定しよう

基本的にblackにはあまり設定できる項目がありませんが、文字の幅や無視するパスを指定できます。 Pythonのプロジェクト配下に pyproject.toml をおいて、以下のように書けます。 この例では「1行の文字数は99文字」という設定と、blackの対象にしないディレクトリーを設定しています。

[tool.black]
line-length = 99
exclude = '''
(
    migrations
    | .mypy_cache
    | .pytest_cache
    | .tox
    | venv
)
'''

書き方はこちらを参照してください。

github.com

blackをプロジェクトに導入しよう

既存のPythonのプロジェクトにblackを導入する場合、単に「コマンドとして使う」だけでは不十分です。 プロジェクト内で定期的に実行して、Pythonコードの品質を保つようにしましょう。

オススメの方法は、 tox.ini やCIで定期的に実行することです。 以下の例は tox.ini に書いて単体テストとして実行する方法です。

[testenv:black]
basepython = python3.7
deps = black
commands =
    black . --check

--check オプションを付けると「blackの書き方に則ってるかどうか」のチェックだけしてくれます。 他にも --diff コマンドで差分表示、 --version でバージョン表示もできるので同時に実行していても良いでしょう。

blackを自動で実行しよう

エディターで実行するようにすると良いです

ただspacemacsは対応中のようです。2019年6月3日現在だとdevelopブランチにはマージされているようです(yapfでなくフォーマッターとしてblackを指定できるようになるようです)。

私はgit の precommitの実行は設定していません。

flake8と共存する

Pythonのプロジェクトであれば flake8 を使っていることと思います。 blackはflake8と併用できますが、併用する場合は一部非互換の部分があるのでちゃんと設定しましょう。

[flake8]
max-line-length = 99
ignore = E203,W503,W504

max-line-length はblackと同じ幅を指定すればOKです。blackはデフォルトで88文字なので、black側で設定しないときはここで88を指定しましょう。 次の ignore は、flake8とblackで 互換がない点を無視するための設定です

isortと共存する

Pythonのモジュールインポート順を自動で修正してくれる isort ともblackは共存できます。 blackはインポート順は直さないですが、isortのデフォルトの書き方に文句を言うので設定します。 以下のように pyproject.tomltox.ini に設定すると良いです(例によって行の文字数は99文字に設定しています)。

[tool.isort]
include_trailing_comma = true
line_length = 99
multi_line_output = 3

これは pyproject.toml に書いた例です。 細かい話ですが、isortを pyproject.toml で設定したい場合は pip install isort[pyproject] でインストールしましょう。

まとめ

blackは

  • PEP8より制限のきついルール
  • 色々設定できない
  • 使いやすい

スペシャルサンクス

aodag さんに実際のプロジェクトでどう使ってるかを色々と教えてもらいました (上記の --check オプションについてや、エディターの設定など)。

blackについてはaodagさんのこのトークでも紹介されてます。他にもPythonのプロジェクトにおいて効率的に開発する方法が説明されてますので参考にしてください。

speakerdeck.com