[解決済み] ネストされた関数のローカル変数
質問
何が起こっているのか理解するのを助けてください。
from functools import partial
class Cage(object):
def __init__(self, animal):
self.animal = animal
def gotimes(do_the_petting):
do_the_petting()
def get_petters():
for animal in ['cow', 'dog', 'cat']:
cage = Cage(animal)
def pet_function():
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
funs = list(get_petters())
for name, f in funs:
print name + ":",
f()
与える。
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
では基本的に、なぜ私は3種類の動物を手に入れることができないのか?それは
cage
はネストされた関数のローカルスコープに「パッケージ」されているのでしょうか?そうでない場合、ネストされた関数への呼び出しはどのようにローカル変数を検索するのでしょうか?
私は、この種の問題に遭遇することは、通常、1つが「間違っている」ことを意味することを知っていますが、何が起こるかを理解したいと思います。
どのように解決するのですか?
ネストされた関数は、定義時ではなく、実行時に親スコープから変数を参照します。
関数本体がコンパイルされ、「自由な」変数(代入によって関数自体で定義されていない)が検証された後、クロージャセルとして関数にバインドされ、コードは各セルを参照するためにインデックスを使用します。
pet_function
このように
1 つ
自由変数 (
cage
) があり、それがクロージャのセル (インデックス 0) から参照されます。クロージャはローカル変数
cage
の中にある
get_petters
関数を使用します。
実際にこの関数を呼び出すと、そのクロージャの値は
cage
の値を周囲のスコープ
の値を見るために使われます。
. ここに問題がある。関数を呼び出すまでに
get_petters
関数はすでにその結果を計算し終えています。そのため
cage
ローカル変数は、その実行中のある時点で、それぞれの
'cow'
,
'dog'
そして
'cat'
という文字列がありますが、関数の最後には
cage
にはその最後の値
'cat'
. このように、動的に返される各関数を呼び出すと、値
'cat'
がプリントされる。
回避策としては、クロージャに頼らないことです。この場合は 部分関数 を作成し、その代わりに 新しい関数スコープ を作成するか、あるいはその変数を キーワードパラメータのデフォルト値 .
-
部分的な関数の例。
functools.partial()
:from functools import partial def pet_function(cage=None): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
-
新しいスコープの例を作成する。
def scoped_cage(cage=None): def pet_function(): print "Mary pets the " + cage.animal + "." return pet_function yield (animal, partial(gotimes, scoped_cage(cage)))
-
キーワードパラメータのデフォルト値として変数をバインドします。
def pet_function(cage=cage): print "Mary pets the " + cage.animal + "." yield (animal, partial(gotimes, pet_function))
を定義する必要はありません。
scoped_cage
関数を定義する必要はなく、コンパイルは一度だけ行われます。
関連
-
[解決済み] 関数内でグローバル変数を使用する
-
[解決済み] Pythonで静的なクラス変数は可能ですか?
-
[解決済み] JavaScriptの変数のスコープとは何ですか?
-
[解決済み] ローカルディレクトリからrequirements.txtファイルに従ってpipを使用してパッケージをインストールするにはどうすればよいですか?
-
[解決済み] JavaScriptの静的変数
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】なぜpythonのネストされた関数はクロージャと呼ばれないのですか?
-
[解決済み】JavaScriptのクロージャと無名関数の比較
-
[解決済み] Django Rest Framework ファイルアップロード
-
[解決済み] CSVデータを処理する際、1行目のデータを無視する方法を教えてください。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] googletransがエラー 'NoneType' オブジェクトに 'group' 属性がない、と言って動かなくなった。
-
[解決済み] 文字列から先頭と末尾のスペースを削除するには?
-
[解決済み] ファブリック経由でデプロイユーザとしてvirtualenvを有効化する
-
[解決済み] 文字列のリストを内容に基づいてフィルタリングする
-
[解決済み] PyQtアプリケーションのスレッド化。QtスレッドとPythonスレッドのどちらを使うか?
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] matplotlib でプロットの軸、目盛、ラベルの色を変更する方法
-
[解決済み] Flaskで非同期タスクを作る
-
[解決済み] virtualenv の `--no-site-packages` オプションを元に戻す。
-
[解決済み] Pandasのデータフレーム内の文字列を'date'データ型に変換するにはどうしたらいいですか?