ホームページ  >  記事  >  バックエンド開発  >  クロージャとは何ですか? Python クロージャに関する問題に対する 2 つの解決策

クロージャとは何ですか? Python クロージャに関する問題に対する 2 つの解決策

Y2J
Y2Jオリジナル
2017-05-04 14:54:331487ブラウズ

クロージャは、異なる構成情報に基づいて異なる結果を取得することです。この記事を通じて、Python クロージャに関する 2 つのメモを共有します。必要な友人は参照してください

クロージャとは何ですか?

簡単に言えば、クロージャは異なる設定情報に基づいて異なる結果を取得します。

専門的な説明を見てみましょう: Closure は Lexical Closure の略語で、 自由な 変数 参照する 関数 です。参照された自由変数は、関数が作成された環境を離れた後も関数とともに残ります。したがって、クロージャは関数とそれに関連する参照環境で構成されるエンティティである、という別の言い方もできます。

遅延バインディング

Python クロージャ関数によって参照される外部自由変数は遅延バインドされます。

Python

In [2]: def multipliers():
  ...:   return [lambda x: i * x for i in range(4)] 
In [3]: print [m(2) for m in multipliers()]
[6, 6, 6, 6]
In [2]: def multipliers():
  ...:   return [lambda x: i * x for i in range(4)] 
In [3]: print [m(2) for m in multipliers()]
[6, 6, 6, 6]

上記のコードのような: i は、クロージャ関数によって参照される外部スコープ内の自由変数です。ループのため、変数 i の値は、内部関数が呼び出された場合にのみ検索されます。が終了した場合、i は最終値 3 を指すため、各関数呼び出しは同じ結果を取得します。

解決策:

1) クロージャ関数の生成時にすぐにバインドします (

関数のデフォルト値を使用します

仮パラメータ):Python

In [5]: def multipliers():
  return [lambda x, i=i: i* x for i in range(4)]
    ...: 
In [6]: print [m(2) for m in multipliers()]
[0, 2, 4, 6]
In [5]: def multipliers():
  return [lambda x, i=i: i* x for i in range(4)]
    ...: 
In [6]: print [m(2) for m in multipliers()]
[0, 2, 4, 6]

上記のコードのような: クロージャ関数を生成するときに、各クロージャ関数には、デフォルト値 i=i を持つパラメータがあることがわかります。このとき、インタプリタは i の値を見つけてそれを仮パラメータ i に割り当て、クロージャ関数の外側のスコープ (That) を生成します。外側のループで)、変数 i が見つかり、その現在値が仮パラメータ i に割り当てられます。

2) functools.partial:

Python

In [26]: def multipliers():
  return [functools.partial(lambda i, x: x * i, i) for i in range(4)]
  ....: 
In [27]: print [m(2) for m in multipliers()]
  [0, 2, 4, 6]
In [26]: def multipliers():
  return [functools.partial(lambda i, x: x * i, i) for i in range(4)]
  ....: 
In [27]: print [m(2) for m in multipliers()]
  [0, 2, 4, 6]

を使用します。上記のコードのように: バインディングの遅延により問題が発生する可能性がある場合、自由変数がバインドされるように functools.partial を通じて部分関数を構築できます。機能的には最初にクロージャー。

クロージャー関数で参照された自由変数を再バインドすることは禁止されていますPython

def foo(func):
  free_value = 8
  def _wrapper(*args, **kwargs):
    old_free_value = free_value #保存旧的free_value
    free_value = old_free_value * 2 #模拟产生新的free_value
    func(*args, **kwargs)
    free_value = old_free_value
  return _wrapper
def foo(func):
  free_value = 8
  def _wrapper(*args, **kwargs):
    old_free_value = free_value #保存旧的free_value
    free_value = old_free_value * 2 #模拟产生新的free_value
    func(*args, **kwargs)
    free_value = old_free_value
  return _wrapper

上記のコードは、UnboundLocalError: local variable 'free_value' Referenced before assigning というエラーを報告します。上記のコードは、次のことを目的としています。特定の初期化状態

(free_value) を持つ A デコレーターを実装しますが、内部クロージャー関数の実行時にオンデマンドで新しい状態 (free_value = old_free_value * 2) に変更できますが、内部の再バインディングにより、インタープリターは free_value をローカル変数であり、old_free_value = free_value の場合、インタープリタは free_value が値を割り当てられずに参照されていると考えるため、エラーが報告されます。

解決策:

クロージャー関数によって参照される自由変数を変更する場合は、この方法で、free_value = [8]、free_value は変更できませんが、free_value[0] をリストに入れることができます。 安全

変更されています。

さらに、Python 3.x では、この問題も解決できる nonlocal キーワードが追加されました。

【関連おすすめ】

1.

Python無料ビデオチュートリアル

3. Pythonオブジェクト指向ビデオチュートリアル

以上がクロージャとは何ですか? Python クロージャに関する問題に対する 2 つの解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。