Pythonには「Pythonic(パイソニック)」と呼ばれる、Python特有の機能や慣習を活かした「推奨される書き方」が存在します。他のプログラミング言語の癖をそのまま持ち込んだり、冗長な記述を続けたりすることは「アンチパターン」と呼ばれ、可読性や保守性を下げる原因となります。
この記事では、よく見られるアンチパターンと、それを改善したコード例を対比形式で紹介します。
1. 連続した比較演算子を使う
数値が特定の範囲内にあるかどうかを判定する際、and を使って式を連結する必要はありません。
アンチパターン:
age = 25
# 他の言語では一般的だが、Pythonでは冗長
if 18 <= age and age < 60:
print("現役世代です")
改善後: 数学の不等式のように、比較演算子を連結して記述できます。
Python
age = 25
# 直感的で読みやすい
if 18 <= age < 60:
print("現役世代です")
2. 複数の値との一致判定には in を使う
ある変数が、複数の候補のいずれかと一致するかを調べる際、or で繋ぐのは非効率です。
アンチパターン:
role = "editor"
if role == "admin" or role == "editor" or role == "moderator":
print("管理画面にアクセス可能です")
改善後: タプルやセットと in 演算子を使うことで、条件を簡潔にまとめられます。
Python
role = "editor"
# 候補をタプルにまとめる
if role in ("admin", "editor", "moderator"):
print("管理画面にアクセス可能です")
3. True/False の判定(真偽値判定)
ブール値や、リストの空/非空を判定する際、== True や len() > 0 と書く必要はありません。
アンチパターン:
is_valid = True
user_list = ["user1"]
if is_valid == True:
print("有効です")
if len(user_list) > 0:
print("ユーザーが存在します")
改善後: Pythonでは、条件式に変数を直接記述すると、自動的に真偽値として評価されます(PEP 8推奨)。
True, 0以外の数値, 空でないコンテナ → TrueFalse,None, 0, 空のコンテナ([],"",{}) → False
is_valid = True
user_list = ["user1"]
if is_valid:
print("有効です")
if user_list:
print("ユーザーが存在します")
4. 三項演算子の活用(条件式)
単純な条件分岐で変数に値を代入する場合、if-else ブロックを広げるとコードが縦に長くなります。
アンチパターン:
score = 85
result = ""
if score >= 80:
result = "Pass"
else:
result = "Fail"
改善後: 条件式(三項演算子)を使うことで、1行で記述できます。
score = 85
result = "Pass" if score >= 80 else "Fail"
5. シーケンスのループにカウンタ変数は不要
リストの要素にアクセスするために、len() と range() でインデックス(カウンタ)を生成するのは、Pythonでは推奨されません。
アンチパターン:
fruits = ["Apple", "Banana", "Cherry"]
# インデックスを使って要素にアクセスする C言語スタイル
for i in range(len(fruits)):
print(fruits[i])
改善後: for 文にリストを直接渡せば、要素を先頭から順に取り出せます。
fruits = ["Apple", "Banana", "Cherry"]
# 要素を直接取り出す
for fruit in fruits:
print(fruit)
6. 同じ値なら同時に代入する
複数の変数を同じ初期値で初期化する場合、行を分ける必要はありません。
アンチパターン:
x = 0
y = 0
z = 0
改善後: = を繋げることで、一度に初期化できます。
x = y = z = 0
7. リスト内包表記の活用
既存のリストから新しいリストを作成する際、空のリストを作って append を繰り返すのは冗長であり、処理速度もやや劣ります。
アンチパターン:
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for n in numbers:
squared_numbers.append(n ** 2)
改善後: リスト内包表記を使うことで、簡潔かつ高速に記述できます。
numbers = [1, 2, 3, 4, 5]
squared_numbers = [n ** 2 for n in numbers]
8. グローバルな名前(組み込み関数名)の上書きに注意する
変数名に list, str, sum, id などの組み込み関数名を使用すると、本来の機能が使えなくなります(シャドーイング)。
アンチパターン:
# 'list' という変数名は避けるべき
list = [10, 20, 30]
# 本来の list() 関数が使えなくなり、エラーになる
# new_list = list((1, 2))
# TypeError: 'list' object is not callable
改善後: 意味のある変数名、あるいは型名と被らない変数名を使用します。
number_list = [10, 20, 30]
# 本来の機能は維持される
new_list = list((1, 2))
9. 変数の値の入れ替えは一時変数不要
変数の値を交換(スワップ)するために、一時変数(temp)を用意する必要はありません。
アンチパターン:
a = 100
b = 200
temp = a
a = b
b = temp
改善後: Pythonのタプルアンパックを利用すれば、1行でスマートに入れ替えが可能です。
a = 100
b = 200
a, b = b, a
まとめ
これらの書き方は、単にコードを短くするだけでなく、意図を明確にし、バグを減らす効果があります。
- 比較は連結する。
- 複数の候補は
inでまとめる。 - 真偽値判定はシンプルに。
- ループは直接イテラブルを回す。
- 内包表記やアンパックを活用する。
- 組み込み関数名を変数名にしない。
これらを意識して、Pythonicなコードを目指してください。
