Python遅延バインディング問題の原理と解決策
遅延バインディングはクローズド問題に現れる。以下は閉包の例を見ます。は内部関数 があります。内部関数は、外部関数の自由変数 を参照している。内部関数が返されます。
クローズドの利点:は、グローバル変数 の使用を避けることができる。は、静的変数の役割を果たす変数を永続化することができます。
クローズドの欠点:は大量のメモリを消費する可能性があります。 メモリ漏れの原因となる可能性があります。
もちろん欠点は人為的に避けられます。
もう一つは遅延バインディングを引き出す例を見てみよう。
これは結合遅延による結果である。具体的な過程を分析してみます。
3行目を実行すると、まずmultiliers関数を実行し、関数のリスト解析式を実行します。反復するたびに、要素として匿名関数が生成されます。その後、3行目に戻り、戻ったリストの匿名関数を巡回してパラメータ2に入力して実行します。この時の関数は以下のようです。
def noname(x):
return i*x
Pythonが変数の作用ドメインチェーンを検索する順序は順次LEGBであることを知っています。
局所変数(L)->外部関数における局所変数(E)->グローバル変数(G)->内蔵変数(B)
非常に重要な点は、Pythonのスコープがコンパイルされた時に形成されていますが、実行中ではなく、関数のスコープが呼び出された位置とは関係がありません。
この例では、上のnoname関数体のiはどこから来ますか?もちろん、まずmultiliers関数の局所変数を探しに行きます。このときiの値はすでに3なので、このような「難解」な現象が発生します。
今は原因が分かりましたが、どう解決すればいいですか?
反復i値を直接匿名関数の関数に注入することができ、ここでは2つの方法を与える。
パラメータのデフォルト値を設定すると、コンパイル時にデフォルト値が計算されます。
def multiliers_ch 1():
return[lamboda m,x=i:m*x for i in range(4)]
内蔵関数でpartial:
実行結果
print([m(2)form in multiplers_ch 1())(菗[0,2,4,6]
print([m(2)form in multiplers_ch 2()))(ハ[0,2,4,6]
print([m(2)form in multiplers_ch 3())(菗[0,2,4,6]
注:
自由変数:ローカルスコープに結合されていない変数を指します。関数のコード属性にアクセスすることで確認できます。
fun.com.freevars
LEGB:この部分で説明できます。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。
def (n):
def mul(x):
return n*x
return mul
double = gen_mul(2)
doubled_value = double(6)
閉包を満たす点がいくつか見られます。もちろん欠点は人為的に避けられます。
もう一つは遅延バインディングを引き出す例を見てみよう。
def multipliers():
return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()]) # [6,6,6,6]
上記の例は[6,6,6,6,6]を出力します。私達が予想していた[0,2,4,6]ではありません。これは結合遅延による結果である。具体的な過程を分析してみます。
3行目を実行すると、まずmultiliers関数を実行し、関数のリスト解析式を実行します。反復するたびに、要素として匿名関数が生成されます。その後、3行目に戻り、戻ったリストの匿名関数を巡回してパラメータ2に入力して実行します。この時の関数は以下のようです。
def noname(x):
return i*x
Pythonが変数の作用ドメインチェーンを検索する順序は順次LEGBであることを知っています。
局所変数(L)->外部関数における局所変数(E)->グローバル変数(G)->内蔵変数(B)
非常に重要な点は、Pythonのスコープがコンパイルされた時に形成されていますが、実行中ではなく、関数のスコープが呼び出された位置とは関係がありません。
この例では、上のnoname関数体のiはどこから来ますか?もちろん、まずmultiliers関数の局所変数を探しに行きます。このときiの値はすでに3なので、このような「難解」な現象が発生します。
今は原因が分かりましたが、どう解決すればいいですか?
反復i値を直接匿名関数の関数に注入することができ、ここでは2つの方法を与える。
パラメータのデフォルト値を設定すると、コンパイル時にデフォルト値が計算されます。
def multiliers_ch 1():
return[lamboda m,x=i:m*x for i in range(4)]
内蔵関数でpartial:
from functools import partial
def multipliers_ch2():
return [partial(lambda m,x : m * x,i) for i in range(4)]
生成器の遅延計算を利用します。
def multipliers_ch3():
for m in range(4):
yield lambda x: m * x
partialとジェネレータの内容は後で共有します。実行結果
print([m(2)form in multiplers_ch 1())(菗[0,2,4,6]
print([m(2)form in multiplers_ch 2()))(ハ[0,2,4,6]
print([m(2)form in multiplers_ch 3())(菗[0,2,4,6]
注:
自由変数:ローカルスコープに結合されていない変数を指します。関数のコード属性にアクセスすることで確認できます。
fun.com.freevars
LEGB:この部分で説明できます。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。