43

関数がグローバル スコープで宣言された変数を変更する必要がある場合は、グローバル宣言を使用する必要があります。ただし、関数がグローバル変数を読み取る必要がある場合は、グローバル宣言を使用せずに読み取ることができます。

X = 10
def foo():
    global X
    X = 20 # Needs global declaration
def bar():
    print( X ) # Does not need global

私の質問は、Python の設計に関するものです。Python は、グローバル宣言を使用せずにグローバル変数の読み取りを許可するように設計されているのはなぜですか? つまり、代入のみをグローバルに強制し、読み取り時にもグローバルに強制しないのはなぜでしょうか? (それはそれを均一でエレガントにします。)

注:読み取り中はあいまいさがないことがわかりますが、割り当て中は、新しいローカル変数を作成するのか、グローバル変数に割り当てるのかが明確ではありません。しかし、BDFL によるこの不均一なデザインの選択には、より良い理由または意図があることを願っています。

4

4 に答える 4

33

ネストされたスコープを使用すると、変数のルックアップが簡単になります。それらは、ローカルから始まり、defを囲むことから、モジュールグローバル、そしてビルトインまでのチェーンで発生します。ルールは、最初に見つかった一致が勝つことです。したがって、ルックアップに「グローバル」宣言は必要ありません。

対照的に、書き込みでは、書き込むスコープを指定する必要があります。それ以外の場合、関数内の「x = 10」が「ローカル名前空間への書き込み」を意味するのか、「グローバル名前空間への書き込み」を意味するのかを判断する方法はありません。

エグゼクティブサマリー、書き込みでは名前空間を選択できますが、ルックアップでは最初に見つかったルールで十分です。お役に立てれば :-)

編集:はい、これは「BDFLがそう言ったため」ですが、タイプ宣言のない他の言語では、ルックアップの最初に見つかったルールがあり、非ローカル書き込みの修飾子のみが必要になることは珍しくありません。考えてみると、スコープ修飾子は最も一般的でないケース(非ローカル書き込み)でのみ必要になるため、これら2つのルールは非常にクリーンなコードにつながります。

于 2012-04-28T03:31:22.457 に答える
21

明示的は暗黙的よりも優れているからです。

変数を読み取るときにあいまいさはありません。ローカルからグローバルまでスコープを検索すると、常に最初に検出されます。

割り当てる場合、インタープリターが割り当てていると明確に想定できるスコープは、ローカルとグローバルの2つだけです。ローカルへの割り当てが最も一般的なケースであり、グローバルへの割り当ては実際には推奨されていないため、これがデフォルトです。グローバルに割り当てるには、明示的に行う必要があります。このスコープでその変数を使用する場合は常に、グローバルスコープに直接移動する必要があり、何をしているのかがわかっていることをインタプリタに伝えます。Python 3では、「nonlocal」を使用して最も近い囲みスコープに割り当てることもできます。

Pythonで名前を割り当てる場合、この新しい割り当ては、以前に他の名前に割り当てられていた名前とは関係がないことに注意してください。ローカルにデフォルトがなく、Pythonがすべてのスコープを検索して、その名前の変数を見つけて、読み取り時と同じように割り当てようとしていると想像してみてください。関数の動作は、パラメーターだけでなく、囲んでいるスコープに基づいて変化する可能性があります。人生は惨めになるでしょう。

于 2012-04-28T03:42:44.850 に答える
21

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

from module import function

def foo(x):
    return function(x)

ここでの名前functionはグローバルです。global functionこのコードを機能させるように言わなければならない場合、非常に退屈になります。

Xyourと myが異なると言う前にfunction(一方が変数で、もう一方がインポートされた関数であるため)、Python ではすべての名前が同じように扱われることを思い出してください。使用すると、それらの値はスコープ階層で検索されます。必要な場合はglobal X、 が必要global functionです。イク。

于 2012-04-28T03:12:20.767 に答える
7

読み取りではあいまいさはなく、書き込みではあいまいさがないことを自分で言います。したがって、書き込みによるあいまいさを解決するためのメカニズムが必要です。

1つのオプション(おそらく実際にはPythonのはるかに古いバージョンであるIIRCで使用されています)は、書き込みは常にローカルスコープに送られると言うことです。globalそうすれば、キーワードやあいまいさは必要ありません。しかし、グローバル変数に書き込むことはできません(globals()ラウンドアバウトで取得するなどの方法を使用しないと)。そのため、それは素晴らしいことではありません。

変数を静的に宣言する言語で使用される別のオプションは、ローカル(そのスコープで宣言する名前)とグローバル(モジュールスコープで宣言される名前)のすべてのスコープについて、言語実装に事前に通信することです。 。ただし、Pythonには変数が宣言されていないため、このソリューションは機能しません。

もう1つのオプションはx = 3、nameを持つ外部スコープに名前がまだない場合にのみ、ローカル変数に割り当てることですx。直感的に正しいことをするように思えますか?しかし、それはいくつかのひどく厄介なコーナーケースにつながるでしょう。現在、x = 3書き込み先はパーサーによって静的に決定されます。global x同じスコープに存在せず、ローカル書き込みであるか、または存在し、global xグローバル書き込みであるかのいずれかです。ただし、それが何をするかがグローバルモジュールスコープに依存する場合は、実行時まで待機して、書き込みがどこに行くかを決定する必要があります。つまり、関数の呼び出し間で変更される可能性があります。。それについて考えてください。モジュールでグローバルを作成するたびに、その名前をローカル変数名として使用していたモジュール内のすべての関数の動作を変更します。一時変数として使用するモジュールスコープの計算を実行し、モジュール内のすべての関数での使用にtmp別れを告げます。そして、インポートしたモジュールに属性を割り当て、そのモジュールから関数を呼び出すことを含む、あいまいなバグについて考えると、私は震えます。うんtmp

また、別のオプションは、各割り当ての言語実装に、ローカルかグローバルかに関係なく通信することです。これはPythonが採用したものです。ほとんどすべての場合(ローカル変数への書き込み)をカバーする賢明なデフォルトがあることを考えると、デフォルトとしてローカル割り当てがあり、グローバル割り当てを明示的にマークアウトしglobalます。


割り当てにはあいまいさがあり、それを解決するために何らかのメカニズムが必要です。globalそのようなメカニズムの1つです。可能なのはそれだけではありませんが、Pythonのコンテキストでは、すべての代替メカニズムが恐ろしいようです。あなたがどんな「より良い理由」を探しているのか分かりません。

于 2012-04-28T04:04:27.320 に答える