勉強を兼ねて Ruff の lint ルールを全て確認しています。(多分更新していきます…)
主観でおススメ度を 5 段階でつけているので、良ければ参考にしてください。
- 5: デメリットがないため、必ずつけるべき
- 4: 一定の制約がつくが、つけた方が良い
- 3: つけてもつけなくてもいい
- 2: つけない方がいい場面が多い
- 1: つけるべきではない(そんなルールあるのかって感じですが…)
- Pyflakes(F)
- F401(unused-import) 5/5
- F402(import-shadowed-by-loop-var) 5/5
- F403(undefined-local-with-import-star) 4/5
- F404(late-future-import) 5/5
- F405(undefined-local-with-import-star-usage) 5/5
- F406(undefined-local-with-import-star-usage) 5/5
- F407(future-feature-not-defined) 5/5
- F500 台に入る前に – printf 形式の文字列書式について –
- F501(percent-format-invalid-format) 5/5
- F502(percent-format-expected-mapping) 5/5
- F503(percent-format-expected-sequence) 5/5
- F504(percent-format-extra-named-arguments) 5/5
- F505(percent-format-missing-argument) 5/5
- F506(percent-format-mixed-positional-and-named) 5/5
- F507(percent-format-positional-count-mismatch) 5/5
- F508(percent-format-star-requires-sequence) 5/5
- F509(percent-format-unsupported-format-character) 5/5
- F52X 台に入る前に – string の format メソッドについて –
- F521(string-dot-format-invalid-format) 5/5
- F522(string-dot-format-extra-named-arguments) 5/5
- F523(string-dot-format-extra-positional-arguments) 5/5
- F524(string-dot-format-missing-arguments) 5/5
- F525(string-dot-format-mixing-automatic) 5/5
- F541(f-string-missing-placeholders) 5/5
- F601(multi-value-repeated-key-literal) 5/5
- F602(multi-value-repeated-key-variable) 5/5
- F621(expressions-in-star-assignment) 3/5
- F622(multiple-starred-expressions) 5/5
- F631(assert-tuple) 4/5
- F632(is-literal) 5/5
- F633(invalid-print-syntax) 4/5
- F634(if-tuple) 5/5
- F701(break-outside-loop) 5/5
- F702(continue-outside-loop) 5/5
- F704(yield-outside-function) 5/5
- F706(return-outside-function) 5/5
- F707(default-except-not-last) 5/5
- F722(forward-annotation-syntax-error) 5/5
- F811(redefined-while-unused) 5/5
- F821(undefined-name) 5/5
- F822(undefined-export) 5/5
- F823(undefined-local) 5/5
- F841(unused-variable) 5/5
- F842(unused-annotation) 5/5
- F901(raise-not-implemented) 4/5
Pyflakes(F)
Pyflakes(F)は linter のpyflakesにあるルールを Ruff に移植してきたものになります。
そのため、以下のルールの詳細を確認する際は必要に合わせて pyflakes のルール集も参照してください。
F401(unused-import) 5/5
使用していない import に対して警告を出します
余計な import を消すことは循環 import を防ぐことにも繋がりますし、import が綺麗になるのでお勧めです
go 言語のコンパイラも同様の機能がついています
悪い例
import numpy as np # <- unused import
def area(radius):
return 3.14 * radius**2
良い例
def area(radius):
return 3.14 * radius**2
F402(import-shadowed-by-loop-var) 5/5
import したモジュールと同じ名前のループ変数をチェックして警告します
悪い例
from os import path
for path in files:
print(path)
path が被ってしまっています
良い例
from os import path
for filename in files:
print(filename)
余計なバグを産む可能性がありますし、名前を変えることによるデメリットはないので、導入推奨です。
F403(undefined-local-with-import-star) 4/5
ワイルドカードインポート(*)を禁止します。
悪い例
from math import * # <- undefined-local-with-import-star
def area(radius):
return pi * radius**2
import *
を用いています( pi がどこから来たのかって感じですね…)
良い例
from math import pi
def area(radius):
return pi * radius**2
ワイルドカードは名前空間が分かりづらくなりますし、pep8 でも避けるべきと明言されているため、lint に追加推奨です。
F404(late-future-import) 5/5
__future__
のインポートがモジュールの先頭で行われていない場合、警告を出します
悪い例
from pathlib import Path
from __future__ import annotations
良い例
from __future__ import annotations
from pathlib import Path
これは __future__
が最初に import されなかった場合に以下のSyntaxError
を出すためです。百害あって一利なしなので、追加推奨です。
from pathlib import Path
from __future__ import annotations
# >>> SyntaxError: from __future__ imports must occur at the beginning of the file
F405(undefined-local-with-import-star-usage) 5/5
ワイルドカード*
での import が行われていて、かつ名前空間に存在しない変数が存在するとき、警告を出します
悪い例
from math import *
def area(radius):
return pi * radius**2
良い例
from math import pi
def area(radius):
return pi * radius**2
F403 と似ていますが、F403 が import 文自体に対するチェックで、F405 が変数に対するチェックのようです。
上記の悪いサンプルに対して ruff を実行すると、以下の警告が出ます。
ruff check sample.py --show-source
sample.py:1:1: F403 `from math import *` used; unable to detect undefined names
|
1 | from math import *
| ^^^^^^^^^^^^^^^^^^ F403
|
sample.py:6:12: F405 `pi` may be undefined, or defined from star imports
|
4 | def area(radius):
5 |
6 | return pi * radius**2
| ^^ F405
|
F403 があれば 405 は出ることがないように感じますが、とりあえず使用推奨です。
F406(undefined-local-with-import-star-usage) 5/5
モジュール名前空間の外(関数内部など)でワイルドカード*
の import を使用すると警告を出します。
悪い例
def foo():
from math import *
良い例
from math import *
def foo():
...
これも名前空間の非明示的な汚染を防ぐための lint です。
F405 と同様に F403 が入っていれば必要ないように見えますが、とりあえず追加推奨です。
F407(future-feature-not-defined) 5/5
現在の Python version で定義されていない__future__
の import に対して警告を出します
誤った__future__
の import はSyntaxError
になるため、追加推奨です。
F500 台に入る前に – printf 形式の文字列書式について –
F50X は printf 形式と呼ばれる%を用いた文字列書式設定方法についての lint ルールになります。
例としては以下のようなものが挙げられます。
# %sで文字列を埋め込む
print("Hello, %s" % "world")
# %.[x]fで浮動小数点をx桁にフォーマット
pi_value = 3.14159
print("The value of pi is approximately %.2f" % pi_value)
# 文字列の幅を指定
city = "New York"
population = 8500000
print("City: %-15s, Population: %d" % (city, population))
詳細は printf 形式の文字列書式化を参照してください。
ここで、%x
の部分をプレースホルダー
と呼び、x
の部分を変換型と呼びます。s
なら string、d
なら符号付き 10 進整数など様々なものが存在します。
また正式な名称は分かりませんが、便宜的に文字列右の%
以降(上記の例では(city, population)
やpi_value
など)をパラメータ
と呼びます。
このプレースホルダとパラメータには順序付き
と名前付き
の2つのパターンがあります。上に挙げた例は順序付きのもので、プレースホルダーに名前がついておらず、パラメータが tuple になっています。
名前付きの printf 形式の文字列書式はプレースホルダーに名前がつき、パラメータがプレースホルダーの名前を key にした辞書として与えられます。例を以下に挙げます。
# string, intのフォーマット:
data = {"subject": "Math", "score": 90, "student": "Alice"}
print("Subject: %(subject)s, Score: %(score)d, Student: %(student)s" % data)
# 浮動小数点数のフォーマット:
temperature = {"location": "New York", "value": 25.5}
print("Temperature in %(location)s: %(value).2f°C" % temperature)
# 16進数や8進数:
number = {"decimal": 42, "hex": 42, "octal": 42}
print("Decimal: %(decimal)d, Hex: %(hex)x, Octal: %(octal)o" % number)
! printf 形式は古い書き方で、Python3.6 からはf"Hello, {world_str}"
などのf-string
による指定が推奨されています。
(そのため、F50X が問題になることは結果的にあまりないかもしれません。)
F501(percent-format-invalid-format) 5/5
誤った変換型の printf 形式に対して警告を出します。
悪い例
"Hello, %" % "world"
良い例
"Hello, %s" % "world"
そのまま悪い例を実行した場合、ValueError
が raise するため、lint に追加を推奨します。
print("Hello, %" % "world")
# >>> ValueError: incomplete format
F502(percent-format-expected-mapping) 5/5
名前付き placeholder に対して、パラメータが順序付きで指定されていた場合に警告を出します。
悪い例
"%(greeting)s, %(name)s" % ("Hello", "World")
良い例
"%(greeting)s, %(name)s" % {"greeting": "Hello", "name": "World"}
# もしくは
"%s, %s" % ("Hello", "World")
悪い例を実行した場合TypeError
が出るため、追加推奨です。
print("%(greeting)s, %(name)s" % ("Hello", "World"))
# >>> TypeError: format requires a mapping
F503(percent-format-expected-sequence) 5/5
F502 の逆で順序付きプレースホルダーに対して、名前付きパラメータを与えた際に警告を出します。
悪い例
"%s, %s" % {"greeting": "Hello", "name": "World"}
良い例
"%(greeting)s, %(name)s" % {"greeting": "Hello", "name": "World"}
# もしくは
"%s, %s" % ("Hello", "World")
悪い例を実行した場合TypeError
が出るため、lint での矯正推奨です。
print("%(greeting)s, %(name)s" % ("Hello", "World"))
# >>> TypeError: not enough arguments for format string
F504(percent-format-extra-named-arguments) 5/5
printf 形式の文字列書式で名前付きパラメータがプレースホルダーに対して多すぎる場合に警告を出します。
悪い例
"Hello, %(name)s" % {"greeting": "Hello", "name": "World"}
良い例
"Hello, %(name)s" % {"name": "World"}
実行時にエラーにはなりませんがコードが読みづらくなるため、lint に追加推奨です。
print("%(greeting)s, %(name)s" % ("Hello", "World"))
# >>> TypeError: not enough arguments for format string
F505(percent-format-missing-argument) 5/5
printf 形式の文字列書式で名前付きパラメータが少ない場合に警告を出します。
悪い例
"%(greeting)s, %(name)s" % {"name": "world"}
良い例
"Hello, %(name)s" % {"name": "world"}
実行時にエラーになるため、lint 追加推奨です。
print("%(greeting)s, %(name)s" % ("Hello", "World"))
# >>> TypeError: not enough arguments for format string
F506(percent-format-mixed-positional-and-named) 5/5
printf 形式の文字列書式で順序付きプレースホルダーと名前付きプレースホルダーが混ざっている場合に警告を出します。
悪い例
"%s, %(name)s" % ("Hello", {"name": "World"})
良い例
"%s, %s" % ("Hello", "World")
# または
"%(greeting)s, %(name)s" % {"greeting": "Hello", "name": "World"}
実行時にエラーになるため、lint 追加推奨です。
print("%s, %(name)s" % ("Hello", {"name": "World"}))
# >>> TypeError: format requires a mapping
F507(percent-format-positional-count-mismatch) 5/5
F504 と F505 の順序付き printf 形式バージョンで、順序付き printf 形式の文字列書式でプレースホルダーとパラメータの数が異なる場合に警告を出します。
悪い例
"%s, %s" % ("Hello", "world", "!")
良い例
"%s, %s" % ("Hello", "world")
実行時にエラーになるため、lint 追加推奨です。
print("%s, %s" % ("Hello", "world", "!"))
# >>> TypeError: not all arguments converted during string formatting
F508(percent-format-star-requires-sequence) 5/5
*
を用いている printf 形式の文字列書式で、パラメータが順序付き出ない場合に警告を出します。
悪い例
from math import pi
"%(n).*f" % {"n": (2, pi)}
良い例
from math import pi
"%.*f" % (2, pi) # 3.14
実行時にエラーになるため、lint 追加推奨です。
print("%(n).*f" % {"n": (2, pi)})
# >>> TypeError: * wants int
F509(percent-format-unsupported-format-character) 5/5
printf 形式の文字列書式で、変換型が誤っている場合に警告を出します。
悪い例
"Hello, %S" % "world"
良い例
"Hello, %s" % "world"
実行時にエラーになるため、lint 追加推奨です。
print("Hello, %S" % "world")
# >>> ValueError: unsupported format character 'S' (0x53) at index 8
F52X 台に入る前に – string の format メソッドについて –
F52X は"Hello, {}".format("world")
のような string のformat
メソッドを用いて変数を文字列に組み込む形式についての lint ルール になります。
例としては以下のようなものが挙げられます。
print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred', other='Georg'))
# The story of Bill, Manfred, and Georg.
print('{0} and {1}'.format('spam', 'eggs'))
# spam and eggs
print('{1} and {0}'.format('spam', 'eggs'))
# eggs and spam
F521(string-dot-format-invalid-format) 5/5
format メソッドを呼ばれる string の書式が誤っている場合に警告を出します。
悪い例
"{".format(foo)
良い例
"{}".format(foo)
実行時にエラーになるため、lint 追加推奨です。
print("{".format(foo))
# >>> ValueError: Single '{' encountered in format string
F522(string-dot-format-extra-named-arguments) 5/5
format メソッドの引数に使用していない keyword argument がある際に警告を出します。
悪い例
"Hello, {name}".format(greeting="Hello", name="World")
良い例
"Hello, {name}".format(name="World")
実行時にエラーにはなりませんが、バグの原因になるため、lint で矯正することを推奨します。
F523(string-dot-format-extra-positional-arguments) 5/5
format メソッドの引数に使用していない positional argument がある際に警告を出します。
悪い例
"Hello, {0}".format("world", "!")
良い例
"Hello, {0}".format("world")
実行時にエラーにはなりませんが、バグの原因になるため、lint で矯正することを推奨します。
print("Hello, {0}".format("world", "!"))
# >>> Hello, world
F524(string-dot-format-missing-arguments) 5/5
format メソッドの引数の positional argument が足りないときに警告を出します。
悪い例
"{greeting}, {name}".format(name="World") # nameが与えられていない
良い例
"{greeting}, {name}".format(greeting="Hello", name="World")
実行時にKeyError
が発生するため、lint で矯正することを推奨します。
print("{greeting}, {name}".format(name="World"))
# >>> KeyError: 'greeting'
F525(string-dot-format-mixing-automatic) 5/5
format メソッドを呼ばれる string に自動採番の{}
と手動採番の{x}
が混在している時に警告を出します。
悪い例
"{0}, {}".format("Hello", "World")
良い例
"{0}, {1}".format("Hello", "World") # 手動採番
# もしくは
"{}, {}".format("Hello", "World") # 自動採番
実行時にValueError
が発生するため、lint で矯正することを推奨します。
print("{greeting}, {name}".format(name="World"))
# >>> ValueError: cannot switch from manual field specification to automatic field numbering
F541(f-string-missing-placeholders) 5/5
f-string において、プレースホルダーがないときに警告を出します。
悪い例
f"Hello, world!"
良い例
"Hello, world!"
エラーは発生しませんが、f ついていて得することもないので、lint で矯正することを推奨します。
F601(multi-value-repeated-key-literal) 5/5
辞書に同じキーが重複していた時に警告を出します。
悪い例
foo = {
"bar": 1,
"baz": 2,
"baz": 3,
}
foo["baz"] # 3
良い例
foo = {
"bar": 1,
"baz": 2,
}
foo["baz"] # 2
エラーは発生しませんが、バグの原因になるため lint に加えることを推奨します。
F602(multi-value-repeated-key-variable) 5/5
辞書にキーとして同じ変数が重複していた時に警告を出します。
悪い例
bar = "bar-key"
baz = "baz-key"
foo = {
bar: 1,
baz: 2,
baz: 3,
}
foo[baz] # 3
良い例
bar = "bar-key"
baz = "baz-key"
foo = {
bar: 1,
baz: 2,
}
foo[baz] # 2
エラーは発生しませんが、バグの原因になるため lint に加えることを推奨します。
F621(expressions-in-star-assignment) 3/5
スター付きの代入ステートメントで式が多すぎないかどうかをチェックし、警告を出します。
これはあまり意味が理解できませんでした。日常に書いてて問題にならないのであれば、とりあえず lint に加えることを推奨します。
F622(multiple-starred-expressions) 5/5
複数のスター付きの代入ステートメントに対し警告を出します。
悪い例
*foo, *bar, baz = (1, 2, 3)
# >>> SyntaxError: multiple starred expressions in assignment
実行時にエラーになるため、lint に加えることを推奨します。
F631(assert-tuple) 4/5
空でない tuple に対して assert ステートメントを使っている場合に警告を出します。
これは空でない tuple は常にTrue
を返してしまうためで、誤解を産む要因になります。
悪い例
assert (some_condition,)
良い例
assert some_condition
テストにおいて意図的に tuple をTrue
で評価して嬉しい場面がないと思うので、コードをシンプルに保つために lint に加えることを推奨します。
F632(is-literal) 5/5
is
やis not
ステートメントを整数や文字列などの定数リテラルに対して使用していた時に警告を出します。
悪い例
x = 200
if x is 200:
print("It's 200!")
良い例
x = 200
if x == 200:
print("It's 200!")
これはis
やis not
ステートメントはオブジェクトとしての同一性(おそらくアドレス)を確認するため、x is 200
などは常にFalse
を返してしまうためです。
代わりに ==
や!=
を使用します。
この場合のis
は全て意図しない用法になるはずなので、lint で矯正するのが良いと思います。
F633(invalid-print-syntax) 4/5
>>
シンタックスを用いたprint
ステートメントに対して警告を出します。
悪い例
from __future__ import print_function
import sys
print >> sys.stderr, "Hello, world!"
良い例
print("Hello, world!", file=sys.stderr)
# もしくは
import logging
logging.error("Hello, world!")
こんな書き方ができたことを私は初めて知りました…
Python2 自体の書き方みたいです。>>
を用いるメリットはもうないと思われるので lint で矯正してしまうべきだと思います。
F634(if-tuple) 5/5
F632 の類似ルールです。if ステートメントでタプルを評価した時に警告を出します。
悪い例
if (False,):
print("This will always run")
良い例
if False:
print("This will never run")
直観的でない記法は基本的に lint で矯正してしまうべきだと思います。
F701(break-outside-loop) 5/5
break
ステートメントがループの外で用いられた場合に警告を出します。
悪い例
def foo():
break
良い例
def foo():
for _ in range(1):
break
ループの外で break ステートメントが呼ばれた場合、SyntaxError
が raise されるので、lint ルールとして矯正しておくべきだと思います。
F702(continue-outside-loop) 5/5
F701 の continue 版です。
continue
ステートメントがループの外で用いられた場合に警告を出します。
悪い例
def foo():
continue
良い例
def foo():
for _ in range(1):
continue
ループの外で continue ステートメントが呼ばれた場合、SyntaxError
が raise されるので、lint ルールとして矯正しておくべきだと思います。
F704(yield-outside-function) 5/5
yield
, yield from
, await
ステートメントが関数の外で用いられていた場合に警告を出します。
悪い例
class Foo:
yield 1
良い例
class Foo:
def some_func(self):
yield 1
F701, F702 と同様に矯正しておくべきだと思います。
F706(return-outside-function) 5/5
return
ステートメントが関数の外で用いられていた場合に警告を出します。
悪い例
class Foo:
return 1
良い例
class Foo:
def some_func(self):
return 1
F705 と同様に矯正しておくべきだと思います。(というかなんで F705 と分かれているんでしょう)
F707(default-except-not-last) 5/5
エラーを指定せず全てのエラーを対象とするexcept:
がexcept
の並びの最後にない場合に警告を出します。
悪い例
def reciprocal(n):
try:
reciprocal = 1 / n
except:
print("An exception occurred.")
except ZeroDivisionError:
print("Cannot divide by zero.")
else:
return reciprocal
# >>> SyntaxError: default 'except:' must be last
良い例
def reciprocal(n):
try:
reciprocal = 1 / n
except ZeroDivisionError:
print("Cannot divide by zero.")
except:
print("An exception occurred.")
else:
return reciprocal
これは Python がSyntaxError
を raise してしまうからで、意図的に悪い例にあるような書き方が行われることはまずないため、lint に加えてチェックするのが適切だと思います。
F722(forward-annotation-syntax-error) 5/5
前提として、Python ではその時点で定義されていないオブジェクトを返す関数を定義する場合その名前をクォートすることで表現することができます。
def generate_animal() -> "Animal":
return Animal("Dog")
class Animal:
def __init__(self, name: str) -> None:
self.name = name
F722 はクォートされたオブジェクトの型が Python の表現として適切でない(例えばエスケープ文字である"/"が入っているなど)場合に警告を出して教えてくれます。
悪い例
def foo() -> "/":
...
これも意図的に悪い例にあるような書き方が行われることはまずないため、lint に加えてチェックするのが適切だと思います。
F811(redefined-while-unused) 5/5
複数回 import されているモジュールに対して警告を出します。
悪い例
import foo
import bar
import foo # Redefinition of unused `foo` from line 1
良い例
import foo
import bar
不要な import を教えてくれるありがたい lint ルールですね
F821(undefined-name) 5/5
定義されていない変数の使用に対して警告を出します。
悪い例
def double():
return n * 2 # raises `NameError` if `n` is undefined when `double` is called
良い例
def double(n):
return n * 2
このルールは PyCharm でもデフォルトで警告を出すようになっています。実行時に NameError が raise してしまうため、lint の検査対象に加えるべきだと思います。
F822(undefined-export) 5/5
__all__
に未定義の名前があった場合に警告を出します。
悪い例
from foo import bar
__all__ = ["bar", "baz"] # undefined name `baz` in `__all__`
良い例
from foo import bar, baz
__all__ = ["bar", "baz"]
Python では__all__
という特殊な変数をモジュールがワイルドカード*
で import された時に外部にエクスポートする変数の全集合を定義するために使用しますが、その際のヒューマンエラーを防ぐために有用なルールです。
このルールを追加することで損することはまずないので、追加推奨です。
F823(undefined-local) 5/5
local のスコープに定義されていない変数をチェックし、警告を出します。
悪い例
x = 1
def foo():
x += 1
良い例
x = 1
def foo():
global x
x += 1
このルールも F822 と同様にヒューマンエラーを防いでくれる上に追加することで損することはないので、基本的に追加推奨です。
F841(unused-variable) 5/5
一度も使用されていない変数に対して警告を出します。
悪い例
def foo():
x = 1
y = 2 # <- F841
return x
良い例
def foo():
x = 1
return x
このルールも F822 と同様にヒューマンエラーを防いでくれる上に追加することで損することはないので、基本的に追加推奨です。
F842(unused-annotation) 5/5
F841 の親戚で、型アノテーションがついているけど一度も使用されていない変数に対して警告を出します。
悪い例
def foo():
bar: int
このルールもデメリットなしにヒューマンエラーを防いでくれるので lint に加えて矯正推奨です。
F901(raise-not-implemented) 4/5
メソッドが実装されていないことを示す際にNotImplemented
を使用していた場合、警告を出します。
悪い例
class Foo:
def bar(self):
raise NotImplemented
良い例:
class Foo:
def bar(self):
raise NotImplementedError
NotImplemented
は特殊なメソッドのみでもちられているエラーで、基本的に直接呼ばれることはないため、NotImplementedError
を用いることが推奨されています。
非常に特殊なケースを除き、この lint で警告される場合は Error をつけ損ねた時だと思うので、導入推奨です。
コメント