概要(内包表記の「条件付き」は“選ぶ・変換する”を1行で完結させる技)
内包表記に条件を組み込むと、要素を選び(フィルタ)ながら、必要に応じて変換(if-else)までを1行で書けます。for+appendの定番より短く、何をしたいかが明確になります。重要なのは「フィルタ if は末尾」「if-else は式の中」「条件の順番を軽い→重いにする」の3点です。これを守るだけで、読みやすくて速いコードになります。
基本の使い方(ここが重要)
フィルタ条件(if)は最後に書く
内包表記の構文は「[式 for 変数 in イテラブル if 条件]」。末尾の if は“取り込むか捨てるか”のフィルタです。
# 0〜9から偶数だけ選ぶ
evens = [x for x in range(10) if x % 2 == 0]
Python「条件は軽く」「変換は後で」を基本線にすると、無駄な計算を減らせます。
変換を条件で分岐する(if-else は式の中に書く)
「Aならこう変換、Bなら別の変換」を1行にできます。ここでの if-else は“式”で、フィルタではありません。
# 偶数はそのまま、奇数は二乗にする
mixed = [x if x % 2 == 0 else x * x for x in range(6)]
Python「フィルタの if(末尾)」と「式の if-else(先頭)」は役割が違う、が最重要ポイントです。
重要ポイントの深掘り(順序最適化・複数条件・例外と欠損の扱い)
条件の順序は「軽い→重い」にする
最初に安い判定で間引き、重い計算は後回しにします。計算コストの高い関数や正規表現は、必要な要素にだけ適用するのが鉄則です。
def heavy(x): return x**3 - x**2 + x # 例:重い
def cheap(x): return x % 2 == 0 # 軽い
result = [heavy(x) for x in range(10_000) if cheap(x)]
Python複数条件は「and / or」で組み合わせる
複合条件は短絡評価(先に false なら後は評価しない)を活かせます。これも軽い→重いの順に並べます。
# 100未満かつ3の倍数だけ
vals = [x for x in data if x < 100 and x % 3 == 0]
PythonNone や欠損を安全に扱う(guard を先に)
比較できないものが混じると例外の原因になります。まず“存在ガード”で落とし、次に比較します。
rows = [{"score": 85}, {"score": None}, {"score": 92}]
safe = [r for r in rows if r["score"] is not None and r["score"] >= 90]
Python例外発生を避ける(内包に try/except は入れない)
内包は“作る”ための構文です。失敗しやすい処理は小さな関数に切り出して使うのが正解です。
def safe_int(s):
try:
return int(s)
except ValueError:
return None
nums = [n for n in (safe_int(s) for s in strings) if n is not None]
Python実務での使いどころ(テキスト整形・抽出・辞書/集合内包の条件)
テキストの抽出と整形(軽いフィルタ→正規表現)
import re
pat = re.compile(r"[A-Za-z]{3,}")
# 空・短い文字列を捨ててから正規表現
tokens = [m.group(0).lower()
for s in lines if s and len(s) >= 3
for m in pat.finditer(s)]
Python辞書内包の条件(キーや値で選んで変換)
rows = [{"name":"alice","score":85},{"name":"bob","score":70}]
passed = {r["name"]: r["score"] for r in rows if r["score"] >= 80}
Python辞書内包は「何をキーに、何を値に」するかが明確で、読みやすさが高いです。
集合内包で重複排除しつつ条件抽出
# 拡張子集合(空拡張子を捨てる)
exts = {p.suffix.lower() for p in paths if p.suffix}
Python集合内包は自動的に重複が消えるので、正規化に向きます。
ネスト内包で二次元データを条件付きで平坦化
grid = [[1,2,3],[4,5,6],[7,8,9]]
# 偶数だけをフラットに
evens = [v for row in grid for v in row if v % 2 == 0]
Pythonよくある落とし穴の回避(副作用禁止・過度な複雑化・可読性)
副作用(print・書き込み)を内包に入れない
内包は“作る”場所。副作用は通常の for で分けると、意図が明確になり安全です。
values = [f(x) for x in data if cond(x)] # 生成
for x in values: print(x) # 出力
Python過度なネストや条件は分割する
読みにくくなったら素直に分けます。途中結果に名前を与えるだけで理解度が跳ね上がります。
filtered = (x for x in items if cheap_check(x))
result = [heavy(x) for x in filtered if heavy_check(x)]
Python速度が欲しいなら「前取り」する
ループ内で何度も使う関数や属性参照は外で束縛し、コストを下げます。
lower = str.lower
normalized = [lower(w) for w in words if w]
Python例題で身につける(定番から一歩先まで)
例題1:フィルタ+変換(順序最適化)
users = [{"name":"alice","age":25},
{"name":"bob","age":0},
{"name":"cara","age":30}]
adults = [u["name"].capitalize() for u in users if u["age"] >= 20]
Python例題2:if-else でラベル付け
labels = ["偶数" if x % 2 == 0 else "奇数" for x in range(1, 6)]
Python例題3:None を最後に送る安全キー(sorted と併用)
rows = [{"name":"alice","score":85},
{"name":"bob","score":None},
{"name":"cara","score":92}]
safe_key = lambda r: (r["score"] is None, r["score"] if r["score"] is not None else float("inf"))
sorted_rows = sorted(rows, key=safe_key)
passed = [r for r in sorted_rows if r["score"] is not None and r["score"] >= 80]
Python例題4:辞書/集合内包の条件付き
items = {"A":3, "b":2, "C":3, "d":1}
# 値が2以上だけ、小文字キーへ変換
filtered = {k.lower(): v for k, v in items.items() if v >= 2}
names = ["Alice","","Bob","Cara","Bob"]
unique = {n.lower() for n in names if n} # 空を除外して重複排除
Pythonまとめ
「条件付きの内包表記」は、フィルタ(末尾の if)と変換(式の if-else)を正しく使い分けるのが核心です。条件の順序は軽い→重いにし、None など比較不可の値は先にガードして安全に。例外を伴う処理は関数へ切り出し、副作用は内包から分離する。辞書・集合・ネスト内包まで広げれば、抽出・整形・正規化を短く、速く、堅牢に書けます。まずは小さなデータで「フィルタ→変換」の型を体に入れ、読みやすさを最優先に設計しましょう。
