自前ループより標準のコレクション処理
存在チェックや集計のたびに for とフラグ変数で自前ループを書くと、「何をしたいのか」がループの構造に埋もれてしまう。同じ走査ロジックが複数箇所に重複すれば、仕様変更時の修正漏れも起きる。any() / sum() / 内包表記など、言語が備えるコレクション処理に置き換えれば意図が1行で伝わる。
01 延滞している請求書があるかの判定
def has_overdue_invoice(invoices: list[Invoice], today: date) -> bool:
found = False
for invoice in invoices:
if invoice.is_paid:
continue
if invoice.due_date < today:
found = True
break
return founddef has_overdue_invoice(invoices: list[Invoice], today: date) -> bool:
return any(
not invoice.is_paid and invoice.due_date < today
for invoice in invoices
)Python では any / all / sum / max / min とジェネレータ式の組み合わせが、Java の Stream API に相当する基本装備。フラグ変数と break が消えるだけでなく、途中で見つかれば走査が打ち切られる点も自前ループと同じ。
02 経費明細の集計と抽出
def summarize_expenses(expenses: list[Expense]) -> tuple[int, list[str]]:
total = 0
over_limit_titles = []
for expense in expenses:
total += expense.amount
if expense.amount > 30_000:
over_limit_titles.append(expense.title)
return total, over_limit_titlesdef total_amount(expenses: list[Expense]) -> int:
return sum(expense.amount for expense in expenses)
def over_limit_titles(expenses: list[Expense]) -> list[str]:
return [
expense.title
for expense in expenses
if expense.amount > 30_000
]「ループを1回で済ませたい」と複数の目的を詰め込むより、目的ごとに分けた方が読みやすく変更にも強い。明細が数千件程度なら走査回数の差は誤差で、可読性の利得の方がずっと大きい。