2010-11-27 6 views
9

私は、Pythonの可変バインディングがどのように正確に動作しているかを理解しようとしています。これを見てみましょう:python:バインディングのしくみ

def foo(x): 
    def bar(): 
     print y 
    return bar 

y = 5 
bar = foo(2) 
bar() 

これは私にとって妥当と思われる5を出力します。

def foo(x): 
    def bar(): 
     print x 
    return bar 
x = 5 
bar = foo(2) 
bar() 

これは、2が奇妙です。最初の例では、Pythonは実行中に変数を探しますが、メソッドが作成された時点で変数が検索されます。それはなぜそうですか?

これは非常に涼しく、私が好きなように正確に動作します。しかし、私は内部バー関数がそのコンテキストを取得する方法について混乱しています。私は理解したい、ボンネットの下で何が起こるか。

EDIT

私は、ローカル変数が大きい優先順位を持っていることを、知っています。 Pythonが実行中に私が以前呼び出された関数から引数を取る方法を知っているかどうか、私は不思議です。 barfooに作成され、xはこれ以上存在しません。これは、関数が作成されたときにこのxを引数値にバインドしましたか?

答えて

6

を宣言上述した第2の例が何であるかを実装して先行しますclosureと呼ばれます。関数barは、変数xをその周囲のコンテキスト、すなわち関数fooから参照しています。これは、グローバル変数xへの参照に先行します。

も参照してくださいこの質問Can you explain closures (as they relate to Python)?

+0

リンクは偉大なことを説明しました。どうもありがとう。 – gruszczy

0

関数の引数からの "x"がグローバル変数 "x"よりも高い優先順位を持っているため、変わったことはありません。

まず、グローバル変数は大きな悪です。

Pythonは「グローバル」演算子を有する:

>>> def foo(x): 
...  def bar(): 
...   global x 
...   print x 
...  return bar 
... 
>>> x = 5 
>>> bar = foo(2) 
>>> bar() 
5 
0

それはスコープの母校であり、第二の例は、X変数ローカルスコープを使用して、それがグローバル

7

あなたにほのめかしている問題は、Pythonでの変数の動的スコープ対字句の一つです。明示的に言うと、Pythonは以下の4つのスコープを定義します。

  1. 最初に検索された最も内側のスコープは、ローカル名
  2. 最も内側のスコープで始まる検索される任意の囲み機能のスコープが含まれ、非ローカル含むが、非グローバル名
  3. 次から最後のスコープは、現在のモジュールのグローバル名
  4. を含み(最後に検索)最も外側のスコープは、内蔵の最初の例で名前

含むネームスペースであり、Wここでは "y"は関数バーの外で定義され、Pythonはモジュール内でグローバル変数 "y"が見つかるまでチェーンを上に移動します

2番目の例では、 "x"関数foo(x)で定義されたxは、barの中に出力されているとき、囲み関数のスコープに属します。純粋に閉包が定義されています。 pythonでスコープのさらなる研究のために

、私は両方の例では、以下のarticle偉大な読み取り

1

を発見し、ルックアップは実行時に起こります。唯一の違いはローカルに定義された変数xが存在し、ローカルに定義された変数yは存在しないことです。

def foo(x): 
    def bar(): 
     print y 

    return bar 

y = 5 
bar = foo(2) 
bar() 

実行

は... ... print文は yという名前の変数を調べて、その1つを使用すると、プリント「5」だけなので、グローバルな文脈でそれを見つけました。

において...

def foo(x): 
    def bar(): 
     print x 

    return bar 

x = 5 
bar = foo(2) 
bar() 

...ルックアップが発生した場合、スコープ変数xが定義あり - foo関数が呼び出される "5" に固定されています。

重要なことは、引数が関数に渡されるときに引数が評価されるため、外部関数fooが呼び出されたときに渡された引数を評価するということです。これにより、foo関数の文脈でxという変数が効果的に作成されるため、barが実行されるたびに、グローバルに定義された変数ではなくその変数が表示されます。

これはときどき混乱することができ、次のコードのよう:

lst = [] 
for i in range(5): 
    x = i 
    lst.append(lambda: x) 

for func in lst: 
    print func() # prints 4 4 4 4 4 

あなたは実行する必要があります。

lst = [] 
for i in range(5): 
    def _func(x): 
     return lambda: x 

    lst.append(_func(i)) 

for func in lst: 
    print func() # prints 0 1 2 3 4 
関連する問題