クロージャ
- 閉鎖機能意味:1内部関数外部関数を参照するためには、グローバル値に内側から変数2.関数を返します
- 単純に関数定義は、関数で定義された変数の外に参照されている、および機能が定義された環境の外部で実行することができます。私たちは、このような閉鎖関数を呼び出します。実際、クロージャは、関数のより一般的な概念として見ることができます。伝統的な意味で定義され、それはもはや機能ので。
まず、小さな閉鎖機能の例:
outer_func DEF(): loc_list = [] DEF inner_func(名): loc_list.append(LEN(loc_list)+ 1) プリント(「%S%S loc_list =「%(名前、loc_list)) リターンinner_func clo_func_0 = outer_func() clo_func_0( 'clo_func_0') clo_func_0( 'clo_func_0') clo_func_0( 'clo_func_0') clo_func_0( 'clo_func_0') clo_func_1 = outer_func() clo_func_1( 'clo_func_1') clo_func_1( 'clo_func_1')
プログラムの結果:
clo_func_0 loc_list = [1] clo_func_0 loc_list = [1、2] clo_func_0 loc_list = [1、2、3] clo_func_0 loc_list = [1、2、3、4] clo_func_1 loc_list = [1] clo_func_1 loc_list = [1、2]
これは、クロージャー関数であるが、変数の参照は、この変数は、変数タイプ、各関数呼び出しであり、その結果が変化することを意味するリストの種類です。
次の例でシンプルな機能:
書き込ま#マジック機能 DEF FUNC(LST = []): lst.append(1) プリント(LST) 変数のタイプのデフォルトパラメータ使用#避け FUNC() FUNC() FUNC() FUNC() #呼び出し結果を [ 1] [1、1] [1、1、1] [1、1、1、1]
ケースの閉鎖機能では、我々は、少なくとも参照の自由変数クロージャの以下の理解を持つことができます。
- 閉鎖自由変数特定の参照のみと閉鎖参照干渉の関連閉鎖、自由変数の各インスタンス。
- その自由変数修正の閉鎖の例としては、次の呼び出された閉鎖例に渡されます。
この概念は理解することはとても直感的ではないので、罠に陥ることは非常に簡単で使用した場合。
第二に、閉鎖トラップ
トラップ閉鎖機能:
DEF my_func(*引数): FS = [] のIの範囲内の(3): DEF FUNC(): 戻りiは* fs.append(FUNC) リターンFS FS1、FS2、FS3 = my_func() プリント(FS1() ) プリント(FS2()) プリント(FS3()) #运行结果 4 4 4
上記のコードでは、クロージャの誤用の代表例です。プログラムの結果は、我々は結果が0,1,4考えるものではありません。すべての4の実際の結果。
この例では、リターンmy_func閉鎖機能が、3つの閉鎖を含むリストの関数ではありません。この例ではすべて閉鎖機能はかなり特別な場所である親関数で定義された同じ自由変数のすべての参照のリターンです。
しかし、ここで疑問は、なぜループのための変数の変更は、閉鎖機能のすべてに影響しますか?特定の例では、我々はただはっきり互いの閉鎖で参照と同じ自由変数の異なるインスタンスが影響されることはありません示し上記で説明してきました。そして、このビューは絶対に正しいです。
だからここで終わりでは問題がありますか?どのようにこのエラーの根本原因を正確に分析する必要があります。
実際には、重要な問題は、変数の戻り値のため閉鎖リストfsはサイクルを変更し、する前に、この変更はその内部で定義されて参照するすべての機能に影響を与えることです。理由は、その機能のmy_funcクロージャ関数内で定義された関数が定義された関数内だけでなく、戻る前に。
もちろん、この内部変数親関数関数リファレンスは自由変数ではなく、現在のブロック内のローカル変数で定義されていません。
DEF my_func(*引数): FS = [] J = 0 のIの範囲内の(3): DEF FUNC(): 戻りjは*のj個の fs.append(FUNC) J = 2 戻りFS F = my_func() 印刷(F ) #运行结果: [<関数my_func 0x00000000021107B8で<地元> .func。>、<関数my_func <地元> 0x0000000002110840で.func。>、
<関数my_func 0x00000000021108C8で<地元> .func。>]
上記のコード・ロジックは、前の例と同等です。実際の実装内で定義された関数funcの前に、ローカル変数jへの変更は、関数funcの業績に影響を与えますので、ここでは、おそらく、少し良く理解しています。
my_func関数が戻ると、次に、関数funcは、変数jが参考と閉鎖関連する特定の自由変数となる前記閉鎖、内部に定義されています。その後、Cellオブジェクトに保存されている自由変数を分析します。
この例を書き換えラムダ(ラムダ)式を使用:
DEF my_func(*引数): FS = [] のIの範囲内の(3): FUNC =ラムダ:私は* fs.append(FUNC) 戻りFS
上記の分析の後、我々は次のように大きな経験を導き出す:リターンクロージャは、変数または変数以降の変更が発生したすべてのループを参照しません。
値は、閉鎖前に我々は変更を期待できなかったものを親関数で定義された変数の性質上、このルールで参照閉鎖を返されます。
DEF my_func(*引数): FSの= [] のIの範囲内の(3): DEF FUNC(_i = I): 戻り_i * _i fs.append(FUNC) リターンのFS #或者
DEF my_func(*引数):
FS = []
のIの範囲内の(3):
FUNC =ラムダ_i = I:_i * _iの
fs.append(FUNC)
戻りFS
正しいアプローチは、関数の親関数パラメータにローカル変数を割り当てることです。関数が定義されている場合、別の指定パラメータは、他の機能には影響しません、現在の関数の定義のままになります。
また、関数が返された場合、その関数はクロージャ機能ではありません返す親関数で定義されたローカル変数への参照が存在しないことに注意してください。
クロージャの機能:https://www.cnblogs.com/yssjun/p/9887239.html