Pythonにおける変数のスコープを理解する
Pythonにおける変数のスコープ(スコープとは、変数が参照可能な範囲のこと)は主に以下の4つのレベルに分けられます。
- ローカル(Local): 関数内で定義された変数は、その関数内でのみ参照可能です。
- エンクロージング(Enclosing): 外側の関数によって定義された変数が、内側の関数で参照可能です。
- グローバル(Global): スクリプト全体で定義された変数は、どこからでも参照可能です。
- ビルトイン(Built-in): Python言語自体に組み込まれている変数や関数(例:
len
,print
など)。
Pythonでは、変数を参照する際には「LEGBルール」(Local -> Enclosing -> Global -> Built-in)に従います。これは、変数が参照される際の探索順序を意味します。
以下に、各スコープについてのサンプルコードを示します。
# グローバル変数(Global Scope)
global_var = "I am a global variable"
def outer_function():
# エンクロージング変数(Enclosing Scope)
enclosing_var = "I am an enclosing variable"
def inner_function():
# ローカル変数(Local Scope)
local_var = "I am a local variable"
# 各スコープから変数を参照
print(local_var) # ローカル変数
print(enclosing_var) # エンクロージング変数
print(global_var) # グローバル変数
inner_function()
# outer_functionを呼び出す
outer_function()
# ビルトイン関数(Built-in Scope)
print(len("I am a built-in function"))
このサンプルコードでは、outer_function
内でinner_function
が定義されています。inner_function
内のlocal_var
はローカルスコープ、enclosing_var
はエンクロージングスコープ、global_var
はグローバルスコープに存在します。
最後に、len
関数はビルトインスコープに存在する関数です。
このように、Pythonの変数スコープは非常に直感的であり、LEGBルールに従って変数を探索・参照します。
上記のソースですが outer_function の 中に inner_function がありますよね? この場合 inner_functionそのもののスコープは outer_function の中だけということですか?
はい、その通りです。inner_function
はouter_function
の中で定義されているため、そのスコープはouter_function
内に限られます。これは、inner_function
がouter_function
のローカルスコープに存在するということを意味します。
具体的には、outer_function
の外からinner_function
を直接呼び出すことはできません。以下のようなコードはエラーになります。
# これはエラーになる
inner_function()
このようなエラーを避けるためには、inner_function
をouter_function
の外で定義するか、inner_function
をouter_function
の戻り値として返すなどの工夫が必要です。
例えば、outer_function
がinner_function
を戻り値として返す場合:
def outer_function():
def inner_function():
print("I am inner_function.")
return inner_function
# outer_functionを呼び出して、その戻り値(inner_function)を変数に格納
my_inner_function = outer_function()
# 格納した変数を使ってinner_functionを呼び出す
my_inner_function() # Output: "I am inner_function."
このように、関数内で定義された関数(inner_function
)は、その外側の関数(outer_function
)のスコープ内でしか存在しないと考えることができます。ただし、Pythonのクロージャなどを使うと、このような内側の関数を外側からも利用することができます。
Pythonのクロージャってなんだー?
Pythonにおいて、クロージャ(Closure)は外側の関数(エンクロージング関数)によって生成され、内側の関数(ネステッド関数)が外側の関数の変数にアクセスできる特殊な関数の一種です。クロージャを使用すると、内側の関数がその定義が行われたスコープ外でも、外側の関数のローカル変数にアクセスできるようになります。
以下に、クロージャの基本的な使用例を示します。
# エンクロージング関数(外側の関数)
def outer_function(x):
# 外側の関数のローカル変数
outer_variable = x
# ネステッド関数(内側の関数)
def inner_function(y):
# 内側の関数が外側の関数のローカル変数にアクセス
return outer_variable + y
# ネステッド関数を返す
return inner_function
# クロージャを生成
closure = outer_function(10)
# クロージャを実行
result = closure(5) # 10 (outer_variable) + 5 (y) = 15
print(result) # Output: 15
この例では、outer_function
がinner_function
を返しています。inner_function
はouter_function
のローカル変数outer_variable
にアクセスしています。outer_function
を呼び出して得られたinner_function
(ここではclosure
として保存)は、その後独立して呼び出すことができ、outer_variable
の値(この場合は10)を”覚えて”います。
このようにして、クロージャを使うと内側の関数が外側の関数のローカル変数にアクセスできるようになり、その変数の値を保持することができます。これにより、関数の振る舞いを動的に変更したり、状態を持つ関数を作成することが可能になります。