89
102

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Python】クロージャ(関数閉方)とは

Last updated at Posted at 2018-10-01

クロージャの説明

クロージャ(関数閉方)とは外側の変数を記憶した関数です。

# 例1
def func():
    x = 3
    def add3(y):
        return y+x
    return add3

f = func()
print(f(4)) # 7

func 関数は add3 関数を定義してそれを返します。
add3 関数は外側で定義された x を関数内で使用しています。
add3 関数をクロージャ、func 関数をエンクロージャといいます。
x は本来であれば func関数を抜けたところで消滅するfunc 関数におけるローカル変数です。
クロージャを生成したことで x が add3 関数内に記憶されて f(4) で呼び出した時に x が加算されます。

# 例2
def func(name):
    def add_msg(message):
        return "Hi " + name + ":" + message
    return add_msg

f = func("Tanaka")
print(f("how are you?")) # Hi Tanaka:how are you?

例2は add_msg 関数がクロージャで name 変数を記憶したものが func 関数から生成されています。

# 例2の続き
print(f.__code__.co_freevars[0], f.__closure__[0].cell_contents) # name Tanaka

関数 f に記憶されている変数名とその値を確認できます。
尚、クロージャには当然2個以上の変数も記憶できるので、エンクロージャの環境を記憶すると説明されることがあります。

自由変数 と 束縛(バインド)

Pythonの自由変数とはある関数内でローカル変数と自身の引数以外で使われている変数です。
例1で x は add3 の中において 自由変数 です。
同様に例2で name は add_msg にとって 自由変数です。

束縛とは名前を定義することです。
n = "Tanaka" とすれば この代入対象の識別子 n は 束縛されます。
関数を定義すれば関数名が束縛されますし、クラスを定義すればクラス名が束縛されます。
import文ではモジュール名が束縛されます。
つまり名前が何らかのオブジェクトに紐付けされることです。
また自由変数がクロージャ内に記憶されることをクロージャに束縛されると言います。

束縛された変数の更新

# 例3
def func():
    x = 3
    def value(v):
        nonlocal x
        x = v
    def add(y):
        return y+x
    x = 5
    return value, add

v, f = func()
print(f(4)) # 9 = 5 + 4 
v(10) # x の値が 5 → 10 に更新される
print(f(4)) # 14 = 4 + 10

束縛された変数の値を後から更新する必要がある場合は Python 3 で導入された nonlocal で宣言します。
例3では自由変数 x を nonlocal で宣言しておくことで後から value 関数を経由して add 関数内でも束縛されている x を更新しています。

# 例3の続き
print(v.__closure__[0].cell_contents is f.__closure__[0].cell_contents) # True

クロージャvで束縛されている変数 x とfで束縛される変数 x は同一オブジュエクトであることが判ります。

静的(レキシカル)スコープ

クロージャは静的スコープの言語で成り立ちます。
静的スコープとは変数の名前解決がソースコード上で成立するものいいます。
C, Python, Javascriptなどは静的スコープの言語です。
逆に動的スコープとは変数の名前解決が実行時のコースタックにて行われます。
Emacs Lisp, bash シェルスクリプト, powershell などは動的スコープです。
PerlやLispでは定義時に静的スコープか動的スコープかを選択できます。

89
102
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
89
102

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?