カテゴリ: Python 更新日: 2026/02/07

Pythonのクロージャー(Closure)とは?関数内関数とnonlocalの活用

Pythonのクロージャー(Closure)とは?関数内関数とnonlocalの活用
Pythonのクロージャー(Closure)とは?関数内関数とnonlocalの活用

先生と生徒の会話形式で理解しよう

生徒

「Pythonで関数の中に関数を書くときって、どういうメリットがあるんですか?」

先生

「それはクロージャーという仕組みを使うためです。関数の中で別の関数に外側の変数を覚えさせておけるんですよ。」

生徒

「外側の変数を覚える…?ちょっと想像しにくいです!」

先生

「では、一緒にクロージャーとnonlocalの活用方法をやさしく見ていきましょう。」

1. クロージャー(Closure)って何?

1. クロージャー(Closure)って何?
1. クロージャー(Closure)って何?

Pythonにおけるクロージャー(関数閉包)とは、関数の中に定義された「内側の関数」が、その外側にある関数の変数(環境)を記憶し、外側の関数が終わった後でもそのデータを利用できる仕組みのことです。

プログラミング未経験の方には、「専用の記憶スペースを持った魔法の関数」と考えると分かりやすいでしょう。通常の関数は実行が終わると中身のデータを忘れてしまいますが、クロージャーは特定のデータを「自分専用のメモ」として持ち続けることができます。

【未経験者向け】簡単なイメージ例

例えば、「名前を覚えて、挨拶を生成する機械」をイメージしてみましょう。


def make_greeter(name):
    # 外側の関数の変数 'name' を記憶する
    def greeter():
        print(f"こんにちは、{name}さん!")
    
    return greeter

# 「田中さん」専用の挨拶関数を作る
say_hello_tanaka = make_greeter("田中")

# 実行すると、外側で渡した「田中」を覚えている
say_hello_tanaka()

こんにちは、田中さん!

このコードでは、make_greeterという外側の関数が終了した後も、内側のgreetername="田中"という情報をしっかりと握りしめています。このように、「関数」と「それが作られた時の環境(変数)」をセットにして閉じ込めるのが、クロージャーの最大の特徴です。

キーワードは、「関数内関数」によるデータの隠蔽と、状態の保持。これによって、わざわざグローバル変数を使わなくても、安全にデータを管理できる高度なプログラムが書けるようになります。

2. 関数内関数の基本例

2. 関数内関数の基本例
2. 関数内関数の基本例

まずは、関数の中に別の関数を作るイメージから。


def outer():
    message = "こんにちは"

    def inner():
        print(message)

    return inner

func = outer()
func()

こんにちは

inneroutermessageを覚えていて、外でも呼べます。

3. なぜ外側の変数を覚える?状態を保持したいときに便利

3. なぜ外側の変数を覚える?状態を保持したいときに便利
3. なぜ外側の変数を覚える?状態を保持したいときに便利

クロージャーを使うと、関数が自分の状態を覚えておけます。たとえば、呼ぶたびに数を増やすカウンター関数などです。


def make_counter():
    count = 0

    def counter():
        nonlocal count
        count += 1
        return count

    return counter

c = make_counter()
print(c())
print(c())

1
2

ここでnonlocalがポイントです。外側のcountを関数内で書き換えるための宣言です。

4. nonlocalキーワードとは?

4. nonlocalキーワードとは?
4. nonlocalキーワードとは?

nonlocalは、関数内から外側の変数を変更できるようにするキーワードです。なければ新しいローカル変数が作られてしまいます。


def outer():
    x = 5

    def inner():
        nonlocal x
        x += 3
        return x

    return inner

f = outer()
print(f())
print(f())

8
11

これにより、xが関数の呼び出しごとに変わっていく「状態」を維持できます。

5. クロージャーとglobalの違い

5. クロージャーとglobalの違い
5. クロージャーとglobalの違い

globalはプログラム全体の変数を操作しますが、nonlocalはあくまで外側関数の変数だけに限定されます。影響範囲が局所的なので安全です。

6. クロージャーを使う時の注意点

6. クロージャーを使う時の注意点
6. クロージャーを使う時の注意点
  • 複雑なネストは読みにくくなる
  • 状態をどこで変えているか、分かりにくくなる
  • 単純な用途ならクラスを使った方がわかりやすい場合もある

7. クロージャーが便利な実践例

7. クロージャーが便利な実践例
7. クロージャーが便利な実践例

例えば簡単なログ機能を作るときに、呼び出すたびにログ数を覚えたい場合などに有効です。


def logger():
    count = 0

    def log(msg):
        nonlocal count
        count += 1
        print(f"{count}: {msg}")

    return log

log = logger()
log("開始")
log("処理中")

1: 開始
2: 処理中

このように、関数だけで状態を持った「処理の部品」を作れます。

8. まとめ:初心者におすすめの使い方

8. まとめ:初心者におすすめの使い方
8. まとめ:初心者におすすめの使い方
  • まずは関数内関数で動きを確認する
  • 状態を保持したいときはnonlocalを使う
  • あまり深く使いすぎず、コードの見やすさを優先する

まとめ

まとめ
まとめ

ここまでPythonのクロージャー(Closure)とnonlocalキーワードの役割について、基本から実践的なコード例まで詳しく解説してきました。最初は「関数の中にさらに関数を作るなんて、コードが複雑になるだけではないか?」と感じた方も多いかもしれません。しかし、クロージャーの本質を理解すると、Pythonプログラミングにおける設計の幅が劇的に広がります。

クロージャーがもたらす「状態の保持」という魔法

プログラミングにおいて「状態を保持する」という概念は非常に重要です。通常、関数の中で定義された変数は、その関数の実行が終わると同時にメモリから解放され、消えてしまいます。次にその関数を呼び出したときは、また初期状態からスタートすることになります。

しかし、今回学んだクロージャーを利用することで、関数が実行を終えた後も、その内部に閉じた変数を「生き続けさせる」ことが可能になります。これは、グローバル変数を使わずに、特定の関数専用の「秘密の記憶領域」を持たせるようなものです。グローバル変数を多用すると、プログラムのどこからでも書き換えが可能になってしまい、バグの原因(意図しない変数の書き換え)になりやすいですが、クロージャーならその心配がありません。

nonlocalの役割と重要性を再確認

クロージャーを使いこなす上で避けて通れないのがnonlocalキーワードです。Pythonでは、関数の中から外側のスコープにある変数を「参照(読み取り)」することは自由にできますが、「代入(書き換え)」をしようとすると、Pythonはその変数を「その関数内の新しいローカル変数」として扱おうとします。

この挙動を制御し、「新しく変数を作るのではなく、外側の関数の変数を更新したいんだ」と明示的に伝えるのがnonlocalの役割です。この宣言があることで、カウンターの数値を増やしたり、フラグを書き換えたりといった、動的な処理がクロージャー内部で完結するようになります。

実践的な応用:設定値を固定した関数の生成

クロージャーはカウンター以外にも、特定の「設定」を保持した関数を量産する際にも役立ちます。例えば、特定の倍率で計算を行う関数を作る例を見てみましょう。


def multiplier(n):
    # nという「設定値」を保持するクロージャーを作る
    def multiply(x):
        return x * n
    return multiply

# 2倍にする関数を作成
doubler = multiplier(2)
# 10倍にする関数を作成
ten_times = multiplier(10)

print(doubler(5))
print(ten_times(5))

10
50

このように、multiplier関数を一度呼び出すだけで、特定のルールを持った新しい関数(doublerten_times)を簡単に作り出すことができます。これはオブジェクト指向における「インスタンス化」に近い利便性を、より軽量な関数の形で実現していると言えます。

カプセル化と安全なコード設計

クロージャーの最大のメリットの一つは「カプセル化」です。外部から直接 countn といった変数を触ることはできません。必ずクロージャー経由でしか操作できないため、データの整合性が保たれます。大規模な開発において、この「変数のスコープを絞る」という考え方は、安全でメンテナンス性の高いコードを書くための必須テクニックです。

学習のステップアップ:デコレータへの架け橋

実は、Pythonの強力な機能である「デコレータ(Decorator)」も、このクロージャーの仕組みを応用したものです。関数を引数に取り、その前後で特定の処理を追加して新しい関数を返す……というデコレータの動きを理解するためには、今回学んだ「関数を返す関数」と「外側の変数を保持する仕組み」が土台となります。

もし、これからさらにPythonを極めていきたいのであれば、クロージャーの理解を深めた後にデコレータの学習に進むと、スムーズに知識がつながるはずです。まずはシンプルなカウンターや、メッセージを保持する関数を自分で書き写し、nonlocalを付けたり外したりしてエラーの出方を観察するなど、手を動かして「体感」してみてください。

先生と生徒の振り返り会話

生徒

「先生、まとめを読んでクロージャーの凄さがようやく分かってきました!単に『関数の中に関数がある』だけじゃなくて、変数の状態をずっとキープできるのがポイントなんですね。」

先生

「その通りです。特に、グローバル変数を使わずに状態を隠し持てる(カプセル化できる)という点が、プログラミング中級者への第一歩になりますよ。nonlocalの使いどころはバッチリですか?」

生徒

「はい!外側の変数を上書きしたいときは nonlocal、ただ見るだけなら不要、という区別ができました。でも、もし nonlocal を忘れたらどうなるんでしたっけ?」

先生

「良い質問ですね。もし nonlocal を書かずに count += 1 のような代入を行うと、Pythonは『これは新しいローカル変数だ』と勘違いしてしまいます。でも、右辺の count が定義されていないので UnboundLocalError というエラーが出て教えてくれますよ。親切ですよね。」

生徒

「なるほど、エラーが出るから気づけるんですね。あと、クラスを使うのとクロージャーを使うの、どっちが良いか迷いそうです。」

先生

「基本的には、保持したい状態が1つや2つで、シンプルな処理ならクロージャーの方がコードが短くスッキリします。逆に、たくさんのデータ(属性)や、それに対する色々な操作(メソッド)が必要になったらクラスの出番ですね。使い分けが大事です。」

生徒

「状況に合わせて選べるようになりたいです!まずはデコレータの理解を目指して、クロージャーのコードを色々書いて練習してみます。ありがとうございました!」

先生

「その意気です!自分で関数を作って、その中にある変数が『いつまで生きているか』を意識しながらデバッグしてみると、より深い理解が得られますよ。頑張ってくださいね。」

カテゴリの一覧へ
新着記事
New1
Flask
Flaskで非同期フォーム送信(Ajax POST)を実装する方法を解説!初心者でもわかるステップ解説
New2
Python
Pythonで定数を定義する方法!変更されない変数の書き方と命名ルールを初心者向けに解説
New3
Python
PythonでMySQLに接続する方法!pymysqlの基本的な使い方
New4
Flask
FlaskのURLルールとは?ルーティングの基本と動的URLの作り方を解説
人気記事
No.1
Java&Spring記事人気No1
Python
Pythonとは何か?初心者向けにできること・特徴・インストール手順までやさしく解説
No.2
Java&Spring記事人気No2
Flask
Flaskでデータベースを使う基本!SQLAlchemyの導入方法をやさしく解説
No.3
Java&Spring記事人気No3
Python
Pythonでリストの要素を検索・取得する方法!index()やin演算子の活用法
No.4
Java&Spring記事人気No4
Python
Pythonプログラムの書き方を基礎から学ぼう!初心者が覚えるべき文法とは?
No.5
Java&Spring記事人気No5
Flask
Flaskアプリの環境変数をクラウドで安全に設定する方法!初心者のための完全ガイド
No.6
Java&Spring記事人気No6
Python
Pythonで仮想環境(venv)を作る方法!初心者向けに環境構築をステップ解説
No.7
Java&Spring記事人気No7
Python
Pythonのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.8
Java&Spring記事人気No8
Flask
Flaskでクラウド上のメッセージキュー(SQS/PubSub)を扱う完全ガイド!初心者向け解説