Pythonで関数を書くとき、必ず出てくるのがreturnと戻り値です。
しかし「とりあえず書いているけれど、実はよく分かっていない」という方も少なくありません。
この記事では、returnの意味・役割から戻り値の型、実務での使い方までを、図解とサンプルコードを交えながら丁寧に解説します。
returnとは何か
returnの基本的な意味と役割

Pythonにおけるreturnは、関数の処理結果(戻り値)を呼び出し元に返すための命令です。
より正確に言うと、次の2つの動きを同時に行います。
- 戻り値を呼び出し元に渡す
- その時点で関数の実行を終了する
つまり、関数の中でreturnが実行されると、それ以降の行は一切実行されません。
これが、処理の終了条件を明確にしたり、早期終了(early return)を実現したりするために重要なポイントです。
式の評価とreturnの動き

returnは、「値」だけでなく式全体を受け取ります。
Pythonは次の順番で動作します。
returnの右側に書かれた式を評価して、1つの値を求める- 評価結果の値を、関数の戻り値として呼び出し元に返す
- 関数の実行を終了する
例えば次のコードを見てください。
def calc():
# ここで「1 + 2 * 3」という式が評価される
return 1 + 2 * 3
result = calc()
print(result)
7
この場合、1 + 2 * 3が先に計算され、7という値になってから、呼び出し元に返されています。
returnは「計算式そのもの」ではなく、「計算した結果の値」を返すという点が重要です。
関数終了とreturnの関係

returnが実行された瞬間、その関数はそこで終了します。
そのため、returnの後ろに書いた処理は、一切実行されません。
def sample():
print("処理A")
return "終了"
print("処理B") # ここには到達しない
value = sample()
print("戻り値:", value)
処理A
戻り値: 終了
このように、print("処理B")は実行されません。
もしreturnの後に処理を書いてしまった場合、そのコードは「死んだコード(dead code)」になっている可能性が高いので、設計ミスのサインとして見直す必要があります。
戻り値の基本
戻り値とは何か

戻り値とは、関数が計算・処理を行った結果として、呼び出し元に返す値のことです。
関数を「入力を受け取り、出力を返す機械」と考えると、次のように整理できます。
- 引数: 関数に渡す入力データ
- 戻り値: 関数から受け取る出力データ
関数定義側ではreturn 値として戻り値を決め、呼び出し側では受け取る変数 = 関数()という形で、戻り値を変数に保存して利用します。
戻り値の型

Pythonでは、戻り値の「型」は特に宣言しませんが、実際には任意の型を返すことができます。
代表的な戻り値の型を表にまとめます。
| 戻り値の型 | 例 | 主な用途 |
|---|---|---|
| int | 0, 1, 100 | 数値計算、カウント結果 |
| float | 1.5, 3.14 | 小数を含む計算結果 |
| str | “OK” | メッセージや名前などの文字列 |
| bool | True, False | 条件判定の結果 |
| list | [1, 2, 3] | 複数要素を順序付きで返す |
| dict | {“x”: 1} | 名前付きの複数情報を返す |
| tuple | (1, “a”) | 複数の戻り値をまとめて返す(後述) |
| None | None | 戻り値が特にないことを表現 |
例えば、次のようにさまざまな型を返すことができます。
def get_number():
return 42 # int
def get_message():
return "Hello" # str
def is_even(n):
return n % 2 == 0 # bool(True/False)
num = get_number()
msg = get_message()
flag = is_even(10)
print(num, type(num))
print(msg, type(msg))
print(flag, type(flag))
42 <class 'int'>
Hello <class 'str'>
True <class 'bool'>
Pythonの関数は「どんな型でも返せる」柔軟さがあるため、関数設計の自由度が高くなります。
戻り値なし(None)とはどういう意味か

Pythonでは、明示的に何も返さなかった場合でも、実はNoneという値が返されています。
次の2つは同じ意味です。
def func_a():
# returnを書かない
print("処理だけ実行")
def func_b():
print("処理だけ実行")
return # 値を指定しないreturn
どちらも呼び出すとNoneが返されます。
result_a = func_a()
result_b = func_b()
print("func_aの戻り値:", result_a)
print("func_bの戻り値:", result_b)
処理だけ実行
処理だけ実行
func_aの戻り値: None
func_bの戻り値: None
「戻り値なしの関数」=「戻り値がNoneの関数」だと理解すると、動きがはっきりします。
実務では、Noneを「エラー」や「見つからなかった」という特別な状態を表す値として使うこともよくあります。
returnの書き方と使い方
単一の戻り値を返す書き方

最も基本的な形は、1つの値をreturnで返す書き方です。
def add(a, b):
"""2つの数値を足し合わせて結果を返す関数"""
result = a + b
return result # 計算結果を1つだけ返す
sum_value = add(10, 20)
print("結果:", sum_value)
結果: 30
このように、return 値で返し、呼び出し側では変数 = 関数名(…)という形で受け取ります。
「関数は1つの値を返す」のが基本形ですが、Pythonでは複数の値を返すこともできます。
複数の戻り値を返す書き方

Pythonでは、カンマ区切りで値を書くことで、複数の戻り値を返すことができます。
内部的にはtuple(タプル)としてまとめて返されます。
def calc_total_and_average(scores):
"""点数リストから合計と平均を計算して返す"""
total = sum(scores)
avg = total / len(scores)
return total, avg # カンマで区切ると複数の値を返せる
scores = [80, 90, 70]
total, average = calc_total_and_average(scores) # 2つの変数で受け取る
print("合計:", total)
print("平均:", average)
合計: 240
平均: 80.0
もちろん、1つの変数でタプルのまま受け取ることも可能です。
result = calc_total_and_average(scores)
print(result, type(result))
(240, 80.0) <class 'tuple'>
「関数から複数の情報を返したいときは、タプル・リスト・辞書にまとめる」という発想が大切です。
条件分岐(if)とreturnの組み合わせ

条件によって戻り値を変えたい場合は、ifとreturnを組み合わせます。
def judge_score(score):
"""点数に応じて評価文字列を返す"""
if score >= 80:
return "合格"
else:
return "不合格"
print(judge_score(90))
print(judge_score(50))
合格
不合格
ここで重要なのは、すべてのパスで何らかの値をreturnしているかを意識することです。
どこか1つでもreturnを書き忘れると、そこを通ったときにはNoneが返ってしまいます。
def bad_judge(score):
if score >= 80:
return "合格"
# elseを書き忘れている
result = bad_judge(50)
print(result) # Noneになってしまう
None
このようなバグを防ぐには、if/elif/elseをきちんと書くか、関数の最後にデフォルトのreturnを書くことが大切です。
早期returnで処理をわかりやすくする

早期return(early return)とは、エラーや例外的な状態を最初にチェックし、その場で関数を終了させる書き方です。
これにより、ネストが深くならず、読みやすいコードになります。
def get_first_item(lst):
"""リストの最初の要素を返す。空ならNoneを返す。"""
if not lst: # 空リストやNoneなら早期return
return None
# ここに来るのは「lstが空でない」場合だけ
return lst[0]
print(get_first_item([1, 2, 3]))
print(get_first_item([])) # 空リスト
1
None
早期returnを使わないと、次のようにネストが深くなります。
def get_first_item_bad(lst):
if lst:
return lst[0]
else:
return None
小さな例では差が分かりにくいですが、実務コードでは早期returnを活用することで、処理の流れが平坦になり、バグも入りにくくなります。
ループ(for・while)とreturnの挙動

ループの中でreturnを実行すると、その瞬間にループだけでなく関数全体が終了します。
def find_first_even(numbers):
"""リストから最初に見つかった偶数を返す。なければNone。"""
for n in numbers:
if n % 2 == 0:
return n # 見つかった時点で関数終了
# ループを最後まで回っても見つからなかった場合
return None
print(find_first_even([1, 3, 5, 8, 10]))
print(find_first_even([1, 3, 5]))
8
None
この例では、8が見つかった瞬間に関数が終わるため、10は調べられません。
「ループを全部見たいのか」「最初の1件だけで良いのか」を意識して、returnをどこに置くか設計することが重要です。
図解で理解するreturnと戻り値
ステップ実行で見るreturnの流れ

実際に、簡単な関数をステップごとに追ってみます。
def multiply(a, b):
"""2つの数値を掛け合わせて返す"""
c = a * b # ステップ2: 計算
return c # ステップ3: 戻り値を返して関数終了
x = 3
y = 4
z = multiply(x, y) # ステップ1: 関数呼び出し
print(z) # ステップ4: 戻り値が使われる
12
流れを整理すると次の通りです。
- 呼び出し元で
multiply(x, y)に到達すると、処理は関数の先頭にジャンプします。 - 関数内で
c = a * bが実行されます。 return cに到達したら、cの値(12)を持って呼び出し元に戻り、関数は終了します。- 呼び出し元では、
z = multiply(x, y)が「z = 12」と同じ意味になり、次の行print(z)へ進みます。
このように、関数呼び出しは「一時的に関数に飛んで、戻り値を持って帰ってくる」動きをしていると考えると理解しやすくなります。
return値が呼び出し元に渡る仕組み

実際のPythonの内部では、関数を呼び出すたびにスタックフレームという「作業領域」が積み上がります。
- 呼び出し元のフレーム(現在の作業領域)がある
- 関数を呼び出すと、新しいフレームが上に積まれ、その中で処理が行われる
return 値が実行されると、その値を呼び出し元に渡し、関数のフレームは破棄される- 呼び出し元のフレームに戻り、戻り値が変数に代入される
このため、関数の中で作ったローカル変数は、関数が終わると消えるという性質があります。
戻り値として返したい情報は、必ずreturnで明示的に外へ出す必要があります。
def create_message(name):
message = f"こんにちは、{name}さん" # ローカル変数
return message # ここで外へ持ち出す
msg = create_message("太郎")
print(msg)
こんにちは、太郎さん
もしreturnしなければ、messageは関数の終了と共に消えてしまい、呼び出し元からは参照できません。
実務コードでのreturnと戻り値の設計例

実務では、関数の戻り値の設計がコード全体の読みやすさ・安全性に大きく影響します。
シンプルな例として、「ユーザーIDからユーザー情報を取得する関数」を考えます。
def get_user(users, user_id):
"""
ユーザー一覧(dict)から、指定IDのユーザー情報(dict)を返す。
見つからなければNoneを返す。
"""
# usersは {"u1": {...}, "u2": {...}} のような辞書を想定
if user_id in users:
return users[user_id] # 正常時: ユーザー情報を返す
# 見つからない場合はNoneで特別な状態を表現
return None
# ダミーデータ
users_data = {
"u1": {"name": "田中", "age": 30},
"u2": {"name": "佐藤", "age": 25},
}
user = get_user(users_data, "u1")
if user is None:
print("ユーザーが見つかりませんでした")
else:
print("ユーザー名:", user["name"])
ユーザー名: 田中
このパターンでは、次のような設計ポイントがあります。
- 見つかった場合: ユーザー情報(dict)を返す
- 見つからない場合: Noneを返して「未取得」を表現
- 呼び出し元ではNoneチェックを必ず行う
もっと情報量を増やしたい場合は、複数の戻り値を組み合わせる形も考えられます。
def get_user_with_status(users, user_id):
"""
(found, user) の2つを返す。
found: bool(見つかったかどうか)
user: 見つかった場合はユーザー情報、見つからなければNone
"""
if user_id in users:
return True, users[user_id]
return False, None
found, user = get_user_with_status(users_data, "u3")
if not found:
print("ユーザーが見つかりませんでした")
else:
print("ユーザー名:", user["name"])
ユーザーが見つかりませんでした
このように、戻り値にどんな情報を持たせるかを意識的に設計することで、呼び出し元のコードがシンプルで分かりやすくなります。
まとめ
Pythonのreturnは、「値を返す」と「関数を終了する」という2つの役割を持っています。
戻り値は1つでも複数でもよく、型の制限もありませんが、関数ごとに「どんな状況で何を返すか」を一貫して設計することが重要です。
また、早期returnやNoneの活用により、条件分岐やループを含む処理も分かりやすく整理できます。
この記事で学んだ考え方とサンプルコードをもとに、実際のプロジェクトで「戻り値設計」を意識しながら関数を書く練習をしてみてください。
