結論から言うと、処理の役割が変わる場所、名前を付けられる場所、入力と出力を分けて考えられる場所は、関数に切り出す候補です。
Pythonを書いていると、ひとまず1つの場所にまとめて動かし、そのあとで「このままだと読みにくい」と感じることがあります。
ただ、どこで関数に分ければよいかが曖昧だと、細かく分けすぎたり、逆に長いまま放置したりしやすいです。
この記事では、処理を関数に切り出す判断基準を、実際に動くコードを見ながら整理します。
この記事でわかること
完成コード
最初に必ず動くPythonコードを1つ示します。
def validate_order(order):
required_keys = ["customer_name", "items", "is_member"]
for key in required_keys:
if key not in order:
raise ValueError(f"{key} が不足しています。")
if not order["items"]:
raise ValueError("items は1件以上必要です。")
def calculate_total(items, is_member):
subtotal = sum(item["price"] * item["quantity"] for item in items)
shipping_fee = 0 if subtotal >= 5000 else 500
discount = int(subtotal * 0.1) if is_member else 0
return subtotal + shipping_fee - discount
def build_message(customer_name, total):
return f"{customer_name}さんのご注文金額は {total} 円です。"
def process_order(order):
validate_order(order)
total = calculate_total(order["items"], order["is_member"])
return build_message(order["customer_name"], total)
sample_order = {
"customer_name": "佐藤",
"items": [
{"name": "USBケーブル", "price": 1200, "quantity": 2},
{"name": "キーボード", "price": 3200, "quantity": 1},
],
"is_member": True,
}
print(process_order(sample_order))コードのポイント
このコードでは、注文処理を1つの大きな流れとして持ちながら、その中を役割ごとに分けています。
- 入力チェックは
validate_order() - 金額計算は
calculate_total() - 表示用メッセージの作成は
build_message() - 全体の流れをまとめるのは
process_order()
このように、役割が変わる場所で関数を切り出すと、読む側が処理を追いやすくなります。
コードを順番に説明します
主要な処理を分けて説明します。
1. 入力チェックという独立した役割を切り出します
def validate_order(order):
required_keys = ["customer_name", "items", "is_member"]
for key in required_keys:
if key not in order:
raise ValueError(f"{key} が不足しています。")
if not order["items"]:
raise ValueError("items は1件以上必要です。")この部分は、注文データが処理できる形になっているかを確認する役割です。
計算や表示とは目的が違うので、別の関数にすると意味がはっきりします。
ここでの判断基準は、処理の責務が変わっているかどうかです。
「チェックする処理」と「計算する処理」は性質が違うため、分ける価値があります。
2. 計算ルールを1か所にまとめます
def calculate_total(items, is_member):
subtotal = sum(item["price"] * item["quantity"] for item in items)
shipping_fee = 0 if subtotal >= 5000 else 500
discount = int(subtotal * 0.1) if is_member else 0
return subtotal + shipping_fee - discountこの関数では、合計金額を求めることだけに集中しています。
送料や会員割引のように、あとから変更されやすい業務ルールは、関数に閉じ込めると修正しやすくなります。
ここでの判断基準は、ひとかたまりに名前を付けられるかどうかです。
この処理には「合計金額を計算する」という自然な名前を付けられるので、関数として独立させやすいです。
3. 表示用の整形を計算処理から分けます
def build_message(customer_name, total):
return f"{customer_name}さんのご注文金額は {total} 円です。"
def process_order(order):
validate_order(order)
total = calculate_total(order["items"], order["is_member"])
return build_message(order["customer_name"], total)表示メッセージの作成は、金額計算そのものとは別の役割です。
この2つを分けておくと、あとで「画面表示用」と「ログ保存用」で文面を変えたいときにも対応しやすくなります。
ここでの判断基準は、入力と出力が整理できるかどうかです。calculate_total() は数値を返し、build_message() は文字列を返しています。
返す値の種類が変わる場所は、関数を分ける候補になりやすいです。
実務で使うときのポイント
実務では、次の観点で関数に切り出すかどうかを考えると判断しやすいです。
- 処理の目的が変わるなら分けます。チェック、計算、保存、表示は同じ関数に詰め込みすぎないほうが保守しやすいです。
- ひとことで説明できる処理は、関数名にしやすいため切り出しやすいです。逆に名前が曖昧なら、まだ責務が混ざっている可能性があります。
- テストしたい単位で分けるのも有効です。送料計算だけ確かめたいなら、計算処理が独立しているほうが確認しやすいです。
- ただし、数行ごとに無理に分ける必要はありません。短くても役割が1つなら、そのままのほうが読みやすいこともあります。
「同じ処理を再利用するから関数にする」という考え方はよく出てきますが、再利用だけが基準ではありません。
1回しか使わなくても、長くて責務が混ざっている処理は、関数に分ける価値があります。