ホームページ  >  記事  >  バックエンド開発  >  Python クロージャでの変数参照の分析

Python クロージャでの変数参照の分析

巴扎黑
巴扎黑オリジナル
2016-12-08 10:57:021293ブラウズ

タイトルは非常に虎っぽく見えますが、実際には、私はそれを分析とはあえて呼びません。この分野ではまだ足りないところがあります。以前は大丈夫だったかもしれませんが、今では言語を勉強する時間とエネルギーがあまりありません。間違った説明がある場合は、大衆を誤解させないでください。

今回はその問題について直接話しましょう。今日 @neiddy(javaeye) がクロージャの問題について話してくれました。それらのいくつかの例を見るのは非常に興味深く、それを理解したいと思いました。

2 つのコードを見てください:

>>> def foo():
       a = 1
       def bar():
              a = a +1
              return a
       return bar()
 
>>> foo()
Traceback (most recent call last):
  File "<pyshell#73>", line 1, in <module>
    foo()
  File "<pyshell#72>", line 6, in foo
    return bar()
  File "<pyshell#72>", line 4, in bar
    a = a +1
UnboundLocalError: local variable &#39;a&#39; referenced before assignment
>>> def foo():
       a = [1]
       def bar():
              a[0] = a[0] + 1
              return a[0]
       return bar()
 
>>> foo()2

クロージャを通じて関数型プログラミングを体験するのは良い気分です。元のテキストの下には括弧がありません。そうしないと、return 関数自体が無意味になってしまいます。この不思議な現象について話しましょう。記事ではコンテナに変更すれば大丈夫とだけ書かれています。なぜですか?

メモリ管理とメモリ割り当てについていくつかグーグルで調べましたが、ソースコードに頼るしか方法が見つかりませんでした。私はこれまで見たことがありませんし、直接読むのは非効率すぎます。幸いなことに、誰かがそれを要約しており、「Yuhen Q.yuhen」による「詳細な Python プログラミング」を推奨しています。彼は本当に控えめなマスターです。

直接クロージャ部分のコード分析についてはクロージャのセクションで言及されていますが、この奇妙な問題について具体的に説明するメカニズムはありません。

本をもう一度読んで、本の「パラメータ」と「クロージャ」のセクションを参照してください。彼の説明と添付のソースコードに基づいて私の理解を話しましょう。

Yu Chen 氏は章の最後で、「CPython でクロージャを実装する原理は複雑ではありません。率直に言うと、参照される外側のオブジェクトを、毎回再作成される内側の関数オブジェクト (func_closure) にアタッチすることです。」 "

この文は前の文の要約であり、重要な情報も含まれています。つまり、内部関数に対応するオブジェクトは、メモリ オブジェクトのスタックへの外部変数を参照することによって、外部関数の変数にアクセスします。 C 言語コードでは、値によって渡されます。

たとえば、最初のコードの a は実際には 1 を参照しており、それ自体の co_nlocals は 1 です。つまり、ローカル変数は等号の前の a です (これは完全に正しくありませんが、これを理解するのに役立つことを願っています)問題)。これはローカル変数 a であるため、a = a +1 は UnboundLocalError をスローする必要があります。

2番目の質問についても、同様の状況ですが、値渡しであっても、配列内の各位置が指す特定のポインタは変化せず、指定された位置の値は変更されます。 、それがコンテナオブジェクトであれば、それはうまくいきます。

私が嫌いなのは、いつもそれを明確に説明できないと感じることです。実際、これは私が初めて C 言語を学んだときによくプレイしたものです。説明はひどいですが、理解できたと思います。要点を指摘した。次のステップは非常に簡単です。この考え方に従ってコードを検証します。つまり、この値を出力するだけでローカル変数を設定しない場合、コードは実行できるはずです。

rreee

物事は予想通りに起こりました。より詳しく体験するには、Yuhen によって分析されたコードをよく見てください。メカニズムを理解することは大いに役立ちます。 Python はますます面白くなり、Python のアイデアを使ってコードを書くことには多くの利点があります。

ちなみにちなみに

>>> def foo():
       a = 1
       def bar():
              return a
       return bar()
 
>>> foo()
1

このコードはiが破棄されていないことが原因であると記事に書かれていましたが、私も今日メモリ割り当てを検索したときにこのことを発見しました。プログラミングするときは、関数型プログラミングは簡潔で明確である一方で、パフォーマンスを向上させ、カウンターを節約するためにリスト内包表記を使用するように努めるべきです。

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