はじめに
if a > b:
a = b
このコードは過去に私が書いた条件分岐を簡略化したものである。これを見たとき、私は少し読みにくいと感じた。では、読みやすい条件分岐とは何か。私は「文脈を読み取りやすい」「条件が明記されている」の2点と考えた。この記事ではこの2点についてまとめる
前提
この記事では左辺右辺ともに処理によって変化する値が格納された変数の場合を考える。
片方が定数または予測した値を格納した変数の場合は、リーダブルコードにもあるように、左辺に変化する値・右辺に予測できる値の順番にするのが望ましい
1.文脈を読み取りやすい
「文脈を読み取りやすい」とは、条件式と以降の処理で主語が変わらないことである。
先のコードを改めて確認する
if a > b:
a = b
このコードを日本語で表現すると「 a が b より大きい場合、b を a に代入する」となる。条件式の主語は a なのに、次の処理では b が主語になっている。
条件式と次の処理で主語を b で一致するように変えてみる
if b < a:
a = b
「 b が a より小さい場合、b を a に代入する」
主語を合わせた方が、文として読みやすく躓きにくくなる。
2.条件が明記されている
条件が長い場合複雑な場合、また条件を判定するための処理が長い場合、条件式を「変数に格納する」または「真偽値を戻すメソッドを作る」ことをして命名すべきである。
例として2~100の間で素数ならば表示するというコードを挙げる。
Pythonの組み込み関数
-
range(a,b,c)
- a 以上 b 未満の数字の並びを間隔 c ごとに返す。cの初期値は1.2~100ならば
range(2,101)
とする - aがb以上の場合、空の並びを返す(for文が処理されない)。cを負の数にした場合、a以下bより大きい数字の並びを間隔 c ごとに返す
- a 以上 b 未満の数字の並びを間隔 c ごとに返す。cの初期値は1.2~100ならば
-
print()
:標準出力を行う組み込み関数
for i in range(2, 101):
root_i = int(i ** (1 / 2))
ans = True
# 合成数Nは2以上√N以下の約数をもつため、割り切れたら素数ではない
for j in range(2, root_i + 1):
#iが2と3の場合は2以上2未満の整数が存在しないためfor文が処理されない
if i % j == 0:
ans = False
if ans:
print(i)
このコードは「全ての合成数Nは2以上√N以下の約数をもつ」ことを利用して素数判定を行っている
条件自体は「素数か否か」のため複雑ではない。しかし、条件を求めるまでが長く、コードの殆どが真偽値を求める過程になっている。これが長くなると、真偽値を求める過程とそのコードで本当に行いたい処理なのかがわからなくなる。
そのため、真偽値を求める過程を外に出し、名前を付ける
#メインの処理
def main() -> None:
for i in range(2, 101):
if is_prime(i):
print(i)
#引数xが素数かどうか戻す関数
def is_prime(x: int) -> bool:
root_x = int(x ** (1 / 2))
ans = True
for i in range(2, root_x + 1):
if x % i == 0:
ans = False
return ans
素数は英語でprime numberと言うため、is_prime
と命名
切り出した方が条件や条件判定の過程・メインで行いたい処理がわかりやすくなった
まとめ
読みやすい条件分岐にするには、「条件と以降のコードで主語を合わせること」「条件に名前を付けること」が必要だと考えた。この他にもド・モルガンの法則で複雑な条件を整理したり、早期リターンで処理をわかりやすくするなどの手法がある。これらを意識し、他の方が読んでも読みやすいコードを書いていきたい