PythonのLintとFormatter
pythonYAPF
スタイルに沿って整形してくれる、Goでいう go fmt みたいなもの。 デフォルトはPython公式のスタイルガイドPEP8でフォーマットされる。
$ pip install yapf
VSCodeでPythonを書くときは、 Pythonプラグイン を入れてこんな設定をWorkspaceのconfigに入れておいて、 保存した時にフォーマットがかかるようにすると快適。
"editor.formatOnSave": true,
"python.formatting.provider": "yapf"
setup.cfgに次のような項目を追加しスタイルを設定する。
[yapf]
based_on_style = google
column_limit = 120
indent_width = 2
Lint
YAPFでフォーマットされた以下のコードにLintをかける。
class FizzBuzz:
def __init__(self, start=0):
self.num = start
def __iter__(self):
return self
def __next__(self):
self.num += 1
if self.num % 15 == 0:
return "FizzBuzz"
if self.num % 3 == 0:
return "Fizz"
if self.num % 5 == 0:
return "Buzz"
return self.num
if __name__ == "__main__":
fizzBuzz = FizzBuzz()
for i in range(100):
print(next(fizzBuzz))
Pylint
PythonプラグインではデフォルトでPylintが使われる。
$ pip install pylint
必要ならパスをUserのconfigでパスを指定する。
"python.linting.pylintPath": "***"
コマンドライン上で実行するとこんな感じ。
$ pylint main.py
No config file found, using default configuration
************* Module main
C: 22, 0: Final newline missing (missing-final-newline)
C: 1, 0: Missing module docstring (missing-docstring)
C: 1, 0: Missing class docstring (missing-docstring)
R: 1, 0: Too few public methods (0/2) (too-few-public-methods)
C: 20, 4: Invalid constant name "fizzBuzz" (invalid-name)
-----------------------------------
Your code has been rated at 7.22/10
指摘された項目を見ると下の二つは余計かなと感じる。 そんな場合、コメントで # pylint: disable=invalid-name のように書くか、 設定ファイルpylintrcのdisableに追加すれば無視できる。–generate-rc-file でとても長い設定ファイルが生成される。
$ pylint --generate-rcfile > pylintrc
10点満点にしたのがこれ。
"""
FizzBuzz main
"""
class FizzBuzz: # pylint: disable=too-few-public-methods
"""
FizzBuzz is incrementing a number and
if the number is divisible by both 3 and 5, output "FizzBuzz",
if divisible by 3, "Fizz",
if divisible by 5, "Buzz",
Otherwise, output the number.
"""
def __init__(self, start=0):
self.num = start
def __iter__(self):
return self
def __next__(self):
self.num += 1
if self.num % 15 == 0:
return "FizzBuzz"
if self.num % 3 == 0:
return "Fizz"
if self.num % 5 == 0:
return "Buzz"
return self.num
if __name__ == "__main__":
fizzBuzz = FizzBuzz() # pylint: disable=invalid-name
for i in range(100):
print(next(fizzBuzz))
Flake8
他のLintとしてFlake8を使うこともできる。これは
- PyFlakes: エラー
- pycodestyle(元pep8): PEP8
- Ned Batchelder’s McCabe script: 循環的複雑度
のチェッカーを合わせたもの。 docstringは別に入れる。
$ pip install flake8 flake8_docstrings
VSCodeでの設定はこんな感じ。Pylintと同時に使うこともできなくはない。
"python.linting.pylintEnabled": false
"python.linting.flake8Enabled": true
同じコードにLintをかけてみる。
$ flake8 main.py
main.py:1:1: D100 Missing docstring in public module
main.py:1:1: D101 Missing docstring in public class
main.py:2:1: D102 Missing docstring in public method
main.py:5:1: D105 Missing docstring in magic method
main.py:8:1: D105 Missing docstring in magic method
main.py:22:30: W292 no newline at end of file
flake8-docstringはPEP257に忠実にチェックしているのでちょっと厳しめ。"# flake8: noqa:D105" のように書くとその場所だけで無視され、setup.cfgでignoreすると全体に適用される。
[flake8]
ignore = D105
exclude =
.git,
__pycache__,
build,
dist
max-complexity = 10
加えてmypyを使うとType Hintsによる型の整合性をチェックできる。