web-dev-qa-db-ja.com

Python 'for'ループのスコープ

Pythonのスコープ規則については聞いていません。私は一般的に理解していますhowスコープはPython forループで動作します。私の質問はなぜこのようにして設計の決定がなされました。例(しゃれはありません):

for foo in xrange(10):
    bar = 2
print(foo, bar)

上記は(9,2)を印刷します。

これは奇妙に思えます。「foo」は実際にループを制御しているだけで、「bar」はループ内で定義されています。 「バー」がループ外でアクセスできる必要がある理由を理解できます(そうでない場合、forループの機能は非常に限られます)。私が理解していないのは、ループが終了した後、制御変数がスコープ内に留まる必要がある理由です。私の経験では、それは単にグローバルな名前空間を乱雑にし、他の言語のインタープリターによってキャッチされるエラーを追跡することを難しくします。

154
chimeracoder

最も可能性の高い答えは、文法を単純に保ち、採用の障害になっていないことであり、ループ構造内で名前を割り当てるときに名前が属するスコープを明確にする必要がないことに多くの人が満足しています。変数はスコープ内で宣言されず、代入ステートメントの場所によって暗示されます。 globalキーワードは、この理由のためにのみ存在します(割り当てがグローバルスコープで行われることを示すため)。

更新

このトピックに関する良い議論は次のとおりです: http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

Forループ変数をループのローカルにするという以前の提案は、ループの終了後に値を保持するループ変数に依存する既存のコードの問題につまずきました。これは望ましい機能と見なされているようです。

要するに、おそらくPythonコミュニティのせいにすることができます:P

93
Jeremy Brown

Pythonにはブロックがありません。他の言語(C/C++やJavaなど)にはありません。したがって、Pythonの有効範囲単位は関数です。

56
atzz

これに対する本当に便利なケースは、enumerateを使用し、最後に合計カウントを取得する場合です。

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

これは必要ですか?いいえ。しかし、確かに便利です。

別の注意事項:Python 2では、リスト内包表記の変数もリークされます。

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

ただし、Python 3には同じことが当てはまりません。

37
carl

ループ内にbreakステートメントがある場合(そして、おそらく後で取得したり、インデックスを作成したり、ステータスを与えたりするために反復値を使用したい場合)、1行のコードと1つの割り当てを節約できるため、便利です。

2
Mac

Pythonの主な影響の1つは、プログラミングの概念を初心者に教えるためにオランダで開発された言語である ABC です。 Pythonの作成者であるGuido van Rossumは、1980年代にABCで数年間働きました。私はABCについてほとんど何も知りませんが、初心者向けであるため、初期のBASICのように、限られた数のスコープを持たなければならないと思います。

1
kindall

まず、変数がループに対してローカルである場合、これらのループはほとんどの実際のプログラミングには役に立たないでしょう。

現在の状況では:

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

45を生成します。次に、Pythonでの割り当ての仕組みを検討します。ループ変数が厳密にローカルである場合:

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

割り当て後のループ内のtotalは、ループ外のtotalと同じ変数ではないため、0を生成します。これは、最適な動作または期待される動作ではありません。

1
Kirk Strauser