コレクション
7-2

早期 continue / break でループ内ネスト解消

ループの中で「対象なら…さらに条件を満たすなら…」と if を重ねると、関数全体の早期 return が使えないぶん深いネストになりやすい。対象外の要素は continue で次へ飛ばし、続行できなくなったら break で打ち切る。ガード節の発想をループに持ち込めば、本処理がフラットに並ぶ。

01 月次決算での経費仕訳の一括計上

Bad

計上できる条件を if で重ねた結果、肝心の計上処理が3段ネストの奥に沈んでいる

ループ内のネストした条件
def post_monthly_expenses(expenses: list[Expense], ledger: Ledger) -> None:
    for expense in expenses:
        if expense.status is Status.APPROVED:
            if expense.has_receipt:
                if not expense.is_posted:
                    ledger.post(expense)
Good

対象外なら continue で即座に次の明細へ。スキップ条件と計上処理が分離される

早期 continue でフラット化
def post_monthly_expenses(expenses: list[Expense], ledger: Ledger) -> None:
    for expense in expenses:
        if expense.status is not Status.APPROVED:
            continue
        if not expense.has_receipt:
            continue
        if expense.is_posted:
            continue
        ledger.post(expense)

continue は「この要素はここで終わり、次へ」という早期 return のループ版。スキップ条件を1行単位で追加・削除できるので、「証憑なしでも1万円未満は計上可」のような仕様変更にも対応しやすい。

02 入金の消込 — 古い請求から充当して残額が尽きたら終了

Bad

「残額があるなら」「未払いなら」と if を重ねていて、残額が尽きたあとも全請求書を空回りで走査し続ける

打ち切らないループ
def apply_deposit(deposit: int, invoices: list[Invoice]) -> int:
    remaining = deposit
    for invoice in sorted(invoices, key=lambda i: i.due_date):
        if remaining > 0:
            if not invoice.is_paid:
                applied = min(remaining, invoice.balance)
                invoice.apply(applied)
                remaining -= applied
    return remaining
Good

残額が尽きたら break で打ち切り、支払済みは continue で飛ばす。充当の本処理だけがネストなしで残る

早期 break + continue
def apply_deposit(deposit: int, invoices: list[Invoice]) -> int:
    remaining = deposit
    for invoice in sorted(invoices, key=lambda i: i.due_date):
        if remaining == 0:
            break
        if invoice.is_paid:
            continue
        applied = min(remaining, invoice.balance)
        invoice.apply(applied)
        remaining -= applied
    return remaining

「この先の要素を処理する意味がなくなった」瞬間に break で抜けるのがポイント。終了条件がループ先頭に明示されるので、フラグ変数で終了を管理するよりも追跡しやすい。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第7章。コード例は原則を自分の題材で表現し直したオリジナル。
7-2

早期 continue / break でループ内ネスト解消

ループの中で「対象なら…さらに条件を満たすなら…」と if を重ねると、関数全体の早期 return が使えないぶん深いネストになりやすい。対象外の要素は continue で次へ飛ばし、続行できなくなったら break で打ち切る。ガード節の発想をループに持ち込めば、本処理がフラットに並ぶ。

01 月次決算での経費仕訳の一括計上

Bad

計上できる条件を if で重ねた結果、肝心の計上処理が3段ネストの奥に沈んでいる

ループ内のネストした条件
def post_monthly_expenses(expenses: list[Expense], ledger: Ledger) -> None:
    for expense in expenses:
        if expense.status is Status.APPROVED:
            if expense.has_receipt:
                if not expense.is_posted:
                    ledger.post(expense)
Good

対象外なら continue で即座に次の明細へ。スキップ条件と計上処理が分離される

早期 continue でフラット化
def post_monthly_expenses(expenses: list[Expense], ledger: Ledger) -> None:
    for expense in expenses:
        if expense.status is not Status.APPROVED:
            continue
        if not expense.has_receipt:
            continue
        if expense.is_posted:
            continue
        ledger.post(expense)

continue は「この要素はここで終わり、次へ」という早期 return のループ版。スキップ条件を1行単位で追加・削除できるので、「証憑なしでも1万円未満は計上可」のような仕様変更にも対応しやすい。

02 入金の消込 — 古い請求から充当して残額が尽きたら終了

Bad

「残額があるなら」「未払いなら」と if を重ねていて、残額が尽きたあとも全請求書を空回りで走査し続ける

打ち切らないループ
def apply_deposit(deposit: int, invoices: list[Invoice]) -> int:
    remaining = deposit
    for invoice in sorted(invoices, key=lambda i: i.due_date):
        if remaining > 0:
            if not invoice.is_paid:
                applied = min(remaining, invoice.balance)
                invoice.apply(applied)
                remaining -= applied
    return remaining
Good

残額が尽きたら break で打ち切り、支払済みは continue で飛ばす。充当の本処理だけがネストなしで残る

早期 break + continue
def apply_deposit(deposit: int, invoices: list[Invoice]) -> int:
    remaining = deposit
    for invoice in sorted(invoices, key=lambda i: i.due_date):
        if remaining == 0:
            break
        if invoice.is_paid:
            continue
        applied = min(remaining, invoice.balance)
        invoice.apply(applied)
        remaining -= applied
    return remaining

「この先の要素を処理する意味がなくなった」瞬間に break で抜けるのがポイント。終了条件がループ先頭に明示されるので、フラグ変数で終了を管理するよりも追跡しやすい。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第7章。コード例は原則を自分の題材で表現し直したオリジナル。