Pythonで関数を書けるようになってくると、ある日ふとこんな違和感を覚えませんか?
「この関数、成功したらリストが返ってくるけど、失敗したらFalse…?」
「呼び出すたびにif文とNoneチェックが増えていくんだけど……」
実はこれ、文法の問題ではなく「戻り値の設計」の問題なんです。
Pythonの関数はとても自由です。数値も文字列も、リストも辞書も、場合によっては関数そのものだって返せます。 でも、その自由さゆえに、設計を意識しない戻り値は、あとからコードを一気に読みにくく、壊れやすくしてしまいます。
特に初心者のうちは、
- 正常時と異常時で戻り値の型が変わる
- FalseやNoneが混在する
- 呼び出し側が「察する」コードになる
といった設計を、悪気なく書いてしまいがちです。 そしてそのツケは、少し規模が大きくなった瞬間にやってきます 😅
この記事では、そんな状態から一歩抜け出すために、
- なぜ戻り値設計が重要なのか
- やってはいけない典型的なNG例
- None・例外・複数戻り値の正しい使い分け
- 「壊れにくく、読みやすい関数」を作る考え方
を、初心者にも分かる言葉で、でも実務でも通用するレベルまで掘り下げて解説していきます。
「なんとなく動くコード」から、
「意図が伝わるコード」へ。
そんな一段レベルアップするためのガイドとして、ぜひ最後まで読んでみてください ✨
なぜ「戻り値設計」が重要なのか
関数はただの処理のかたまりではありません。 「引数を受け取り、結果を返す」という約束(契約)を持った部品です。
この契約が曖昧だと、関数を使う側は常に不安になります。
たとえば、次のような関数があったとします。
def find_user(user_id):
if user_id == 1:
return {"id": 1, "name": "Alice"}
else:
return False
一見すると動きそうですが、使う側はこう考えなければなりません。
- 戻り値は辞書?それともFalse?
- ifで毎回チェックが必要?
- チェックを忘れたらどうなる?
この「考えなければならないこと」が増えるほど、コードは読みにくく、壊れやすくなります。
Pythonは動的型付け言語なので、こうした問題は実行するまで気づけないことも多いです。 その結果、
- ある条件でだけクラッシュする
- NoneTypeエラーが突然出る
- 修正のたびに別の場所が壊れる
といった「よく分からないバグ」に悩まされがちになります。
特に初心者のうちは、
- 「とりあえず動けばOK」
- 「失敗したらFalse返せばいいか」
と考えがちですが、これは後から必ず自分を苦しめます 😌
戻り値設計を意識するというのは、
- 関数が何を返すのかを明確にする
- 使う側が迷わないようにする
- エラーを早く・安全に見つける
ということです。
これは難しいテクニックではありません。 考え方を少し変えるだけで、コードの読みやすさと安心感は驚くほど変わります。

次の章では、その土台となる return文の基本原則 から整理していきましょう。
return文の基本原則を整理しよう
戻り値設計の話に入る前に、まずは return文そのものの性質 をしっかり押さえておきましょう。 ここを曖昧にしたままだと、設計の話がふわっとしてしまいます。
returnが実行された時点で関数は終了する
Pythonでは、return が実行された瞬間に関数の処理は終了します。
def sample():
print("start")
return 10
print("end")
この関数を呼び出すと、出力はこうなります。
start
return の後ろに書いたコードは実行されません。 このようなコードは「デッドコード」と呼ばれ、可読性を下げる原因になります。
returnを書かないとNoneが返る
初心者が意外と見落としがちなのが、このルールです。
def do_nothing():
pass
この関数は何も返していないように見えますが、実際には None を返しています。
また、値を書かずに return だけを書いた場合も同じです。
def do_nothing():
return
Pythonでは「何も返さない関数」=「Noneを返す関数」だと覚えておきましょう。
Pythonの関数は何でも返せる
Pythonの関数は非常に柔軟で、さまざまなオブジェクトを戻り値にできます。
- 数値・文字列
- リスト・辞書・タプル
- クラスのインスタンス
- 関数そのもの
この自由さは強力ですが、裏を返すと 「制約がない」 ということでもあります。
だからこそ、
- どんな型を返すのか
- 失敗したときはどうするのか
を決めずに書くと、設計が一気に崩れます。

次の章からは、いよいよ本題です。 「実務で壊れにくい戻り値設計」を、具体例と一緒に見ていきましょう。
戻り値設計の基本パターン
戻り値の型は必ず統一する
戻り値設計でもっとも重要なのが、「関数が返す型を常に一定にする」ことです。
初心者がやりがちなNG例を見てみましょう。
def search_items(keyword):
items = ["apple", "banana", "orange"]
result = [item for item in items if keyword in item]
if result:
return result
else:
return False
この関数は、一見すると親切そうですが、使う側はかなり困ります。
items = search_items("ap")
for item in items:
print(item)
もし False が返ってきたら、ここでエラーになります。 そのため、呼び出し側は毎回こう書かざるを得ません。
items = search_items("ap")
if items is not False:
for item in items:
print(item)
こうしてコードは少しずつ、
- 条件分岐が増える
- 意図が読み取りにくくなる
- 修正が怖くなる
という状態に近づいていきます 😅
改善パターン①:Noneを返す
「見つからなかった」という状態を None で表現するのは、Pythonでは一般的な設計です。
def search_items(keyword):
items = ["apple", "banana", "orange"]
result = [item for item in items if keyword in item]
if result:
return result
return None
これで、戻り値の意味がはっきりします。
- list → 結果あり
- None → 結果なし
改善パターン②:空のコレクションを返す
リストや辞書を返す関数では、空のオブジェクトを返す設計が特におすすめです。
def search_items(keyword):
items = ["apple", "banana", "orange"]
return [item for item in items if keyword in item]
この場合、見つからなければ空のリスト [] が返ります。
呼び出し側は何も考えずに書けます。
for item in search_items("ap"):
print(item)
このシンプルさが、後々の保守性に大きく効いてきます。
戻り値の型を統一するという考え方は、 「たまたま動くコード」から「信頼できるコード」へ変わる最初の一歩です。
この設計思想を、より体系的に学びたい人には次の一冊がとても役立ちます。
Effective Python 第2版
関数設計・戻り値・例外の考え方を、実務視点で深く理解できる定番書です。

次は、複数の値を安全に返す方法について見ていきましょう。
複数の値を安全に返す
関数の中で「結果」と「付加情報」を一緒に返したくなる場面はよくあります。
たとえば、
- 処理結果とステータス
- 計算結果とエラーメッセージ
- 取得データと件数
といったケースです。
Pythonではタプルでまとめて返せる
Pythonでは、カンマ区切りで複数の値を返すと、自動的にタプルとして扱われます。
def divide(a, b):
if b == 0:
return None, "0で割ることはできません"
return a / b, None
呼び出し側では、アンパックして受け取ります。
result, error = divide(10, 2)
if error is None:
print(result)
else:
print(error)
このように、戻り値の意味が明確になり、 「何が返ってくるか分からない」状態を避けられます。
タプルの弱点
ただし、タプルには弱点もあります。
- 要素が増えると意味が分かりにくい
- 順番を間違えてもエラーにならない
次のコード、少し怖くないですか?
value, message, status, retry = some_function()
どれが何なのか、呼び出し側だけでは判断しづらくなってきます。
namedtupleで可読性を上げる
この問題を解決する方法のひとつが namedtuple です。
from collections import namedtuple
Result = namedtuple("Result", ["value", "error"])
def divide(a, b):
if b == 0:
return Result(value=None, error="0で割ることはできません")
return Result(value=a / b, error=None)
呼び出し側は、ドット記法で値にアクセスできます。
result = divide(10, 2)
if result.error is None:
print(result.value)
else:
print(result.error)
これだけで、コードの読みやすさはかなり変わります。
「何番目の値だったっけ?」と悩む時間が減り、 関数の意図が自然に伝わるようになります。

次は、異常系(エラー)をどう設計するかについて解説します。
異常系(エラー)はどう設計するべきか
戻り値設計で多くの人が悩むのが、 「失敗したとき、戻り値で表現するか?例外を投げるか?」という問題です。
ここを曖昧にすると、
- FalseやNoneが大量発生する
- if文だらけのコードになる
- エラーを見逃す
といった状態に陥ります。
Pythonでは「例外」が基本
Pythonでは、回復不能なエラーや契約違反は例外で表現するのが基本です。
たとえば、
- 引数の型が想定と違う
- 本来あり得ない状態に入った
こういったケースを戻り値で表現すると、 呼び出し側がチェックし忘れた瞬間にバグになります。
def get_user_age(user):
if "age" not in user:
raise ValueError("ageが存在しません")
return user["age"]
例外を使えば、
- 問題が起きた瞬間に止まる
- 原因が明確になる
- バグを早期に発見できる
というメリットがあります。
回復可能なエラーは戻り値で表現する
一方で、すべてを例外にすれば良いわけではありません。
たとえば、
- 検索結果が0件
- ユーザー入力が空だった
といった「よくある状態」は、異常ではなく想定内です。
この場合は、
- Noneを返す
- 空のリストを返す
といった戻り値設計の方が自然です。
戻り値と例外の役割を分ける
シンプルな判断基準としては、次のように考えると迷いにくくなります。
- 呼び出し側が対処できる → 戻り値
- 設計ミス・契約違反 → 例外
この線引きを意識するだけで、 関数の責務が一気にクリアになります。
こうした考え方は、実は多くの良書で共通しています。
Clean Code アジャイルソフトウェア達人の技
「関数の責務」「例外の扱い」「一貫した設計」という観点から、 戻り値設計を根本から見直すヒントが詰まった定番書です。

次は、戻り値設計をさらに強化するための 実践的なテクニックをまとめて紹介します。
戻り値設計を強化する実践テクニック
ここまでで、戻り値設計の「考え方」はかなり整理できたと思います。 最後に、日常的なコーディングで効いてくる実践テクニックをまとめておきます。
型ヒントで「戻り値の約束」を明文化する
戻り値設計を一段レベルアップさせてくれるのが、型ヒントです。
def get_user_name(user_id: int) -> str | None:
if user_id == 1:
return "Alice"
return None
これだけで、
- この関数は
strかNoneを返す - Falseや数値は返らない
という契約が一目で分かります。
エディタや静的解析ツールを使っていると、 呼び出し側でのミスも早い段階で検出できるようになります。
複雑な式は一時変数に置く
次のような return、書いたことありませんか?
return a * b / c if c != 0 else None
短くて一見スマートですが、 後から読むと「何をしている関数なのか」が分かりづらくなります。
一度、意味のある名前を付けてから返すだけで印象は変わります。
if c == 0:
return None
result = a * b / c
return result
デバッグもしやすくなり、意図も伝わりやすくなります。
副作用に頼らず、値を返す
戻り値設計が崩れやすいパターンのひとつが、副作用です。
total = 0
def add(value):
global total
total += value
この関数は None を返しますが、 実際には外部の状態を書き換えています。
こうした関数は、使う側からすると挙動が分かりにくくなります。
可能な限り、
def add(total, value):
return total + value
のように、計算結果を戻り値として返す設計を意識しましょう。
ツールの力を借りる
人間の注意力には限界があります。
そのため、
- リンター
- フォーマッター
- 静的解析ツール
を使って、戻り値の揺れや設計ミスを早めに検知するのがおすすめです。

コードの質は、 才能よりも仕組みで安定させる方がずっと確実です。
まとめ
今回は、Python初心者が意外と見落としがちな 「戻り値設計」について、基礎から実践まで整理してきました。
ポイントを振り返ると、次の通りです。
- 戻り値は「関数と呼び出し側の契約」である
- 正常時と異常時で戻り値の型を変えない
- コレクションは空で返す設計が強い
- 複数の値はタプルやnamedtupleで意味を明確にする
- 契約違反や回復不能な状態は例外で表現する
- 型ヒントを使うと設計がコードとして残る
戻り値設計は、最初のうちは地味に感じるかもしれません。 でも実際には、
- if文が減る
- エラーの原因が分かりやすくなる
- 安心してコードを変更できる
といった形で、あとからじわじわ効いてきます。
私自身も、Pythonを書き始めた頃は 「とりあえずFalse返しとけばいいかな?」という設計をよくしていました 😅 でも、ある程度コード量が増えたところで、一気に破綻しました。
それ以来、戻り値は
- 何を返す関数なのか
- 失敗とは何か
- 呼び出し側はどう書けるか
を先に考えてから書くようにしています。
その結果、コードを読む時間も、直す時間も、かなり減りました。
戻り値設計はテクニックというより、考え方です。 ぜひ、次に関数を書くときから、少しだけ意識してみてください。
きっと、「Pythonが前より書きやすくなった」と感じられるはずです ✨
あわせて読みたい
戻り値設計の考え方は、例外設計・型・設計全般と強くつながっています。 理解を一段深めたい方は、次の記事もあわせて読んでみてください。
- Pythonの例外設計入門|try/exceptを「どう設計するか」まで徹底解説
- Python型ヒント実践入門|Type Hintsでコード品質を上げる方法
- Pythonの「小さな設計ミス」が後で地獄を見るパターン10選
- Pythonで作る「壊れにくいスクリプト」共通設計5原則
これらの記事を読むことで、 「戻り値」だけでなく 設計として一貫したPythonコード が書けるようになります。
参考文献
- Real Python|The Python return Statement
- paizaラーニング|Pythonのreturn文の使い方
- Stack Overflow|Best practice in Python for return value on error vs success
- Software Engineering Stack Exchange|Good practice for returns in Python
- TechGym|Pythonのmap・filter・reduceの使い方
- Zenn|Python設計・戻り値に関するメモ
- Docswell|Python設計・戻り値と例外に関する資料
よくある質問(Q&A)
- Q戻り値にNoneを使うのは危険ではありませんか?
- A
結論から言うと、正しく設計されていれば危険ではありません。
Noneが問題になるのは、「Noneが返る可能性があること」がコードから読み取れない場合です。 型ヒントや関数名、ドキュメントで意図が明確になっていれば、Noneはとても分かりやすい表現になります。
特に「見つからなかった」「存在しなかった」という状態は、FalseよりもNoneの方が意味が明確です。
また、リストや辞書を返す関数であれば、Noneではなく空のコレクションを返す設計にすることで、 呼び出し側のNoneチェック自体を不要にできます。
- QFalseを戻り値として使う設計は全部ダメですか?
- A
すべてがダメというわけではありませんが、初心者にはおすすめしません。
Falseは
0や空のコレクションと同じ「偽」として扱われるため、 意図しない条件分岐に入りやすいという欠点があります。「成功・失敗」を表したい場合でも、Noneや例外、あるいは明示的なResultオブジェクトの方が、 コードの意味がはっきりします。
どうしてもTrue / Falseを返したい場合は、 「判定だけを行う関数」であることが明確なケースに限定すると安全です。
- QResult型のような設計は初心者でも使うべきですか?
- A
最初から無理に使う必要はありません。
Result型は、例外を使わずにエラーを安全に伝えたい場合にとても強力ですが、 考え方としては少し抽象度が高めです。
まずは、
- 戻り値の型を統一する
- Noneと例外を正しく使い分ける
この2点をしっかり身につけるだけで、コードの品質は大きく向上します。
その上で、「例外を使わない設計が欲しくなった」と感じたタイミングで、 Result型の考え方を取り入れるのがおすすめです。







※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。
※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。