Pythonの「for」ループでのスコープ


177

Pythonのスコープ規則については質問していません。Pythonのループでスコープがどのように機能するか一般的に理解しています。私の質問は、なぜ設計の決定がこのように行われたのかです。例(しゃれは意図されていません):

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

上記は(9,2)を出力します。

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


6
forループがグローバル名前空間を乱雑にしたくない場合は、関数でラップします。大量の閉鎖!
ジェサニズム2010

24
グローバル名前空間でループを実行している場合を除き(一般的ではありません)、ローカル名前空間が乱雑です。
Glenn Maynard

3
これが存在しない場合、ループ内で中断した時点で、後でどのように処理を続行しますか?ループの前に制御変数を定義するだけですか?
内部石2012

9
@endolithええ...なぜそれを必要としないのですか?
Steven Lu

3
まあ人々は彼らが慣れていることを好むつもりです。この種のものは、この種のものに慣れ、別の言語に切り替えるときに苦痛なプロセスを経なければならないpythonコーダーを傷つけると思います。他の人にとっては、これは私が思うにきちんとした小さなショートカットです。
Steven Lu

回答:


107

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

更新

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

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

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


2
誘導変数のスコープがループの本体に限定されている場合、文法はどのように複雑になるでしょうか?このような変更は、文法ではなく、Pythonのセマンティック分析に限定されます。
Charles、

6
Pythonではループはブロックではありません。この種の動作の変更は、文法を根本的に変更するか、特別なケースを提供することを要求します。帰納変数の概念全体も、現在の文法では表現されていません。文法は、インタープリターがどのように解釈するかについての契約を提供します。私の要点は、文法を複雑にすることなく、この動作の変更をどのように行うことができるかを予測できないことです。設計決定の副作用が特徴になっているので、それはすべての問題です。
Jeremy Brown

1
この投稿mail.python.org/pipermail/python-dev/2005-September/056677.htmlは、ブラウン氏が指摘している速度と複雑さに関する詳細を提供しています。
rajesh

61

Pythonには、他の一部の言語(C / C ++やJavaなど)のようにブロックはありません。したがって、Pythonのスコープ単位は関数です。


3
私は混乱しています-関数がスコープされるのと同じ方法でPythonがループをスコープするのを妨げるのは何ですか?
chimeracoder、2010

35
実際にはそうではありません。文法がブロッククレイジーにならないというだけです。(docs.python.org/reference/…)「ブロックは、ユニットとして実行されるPythonプログラムテキストの一部です。次はブロックです:モジュール、関数本体、およびクラス定義...」
Jeremyブラウン

1
@thebackhand、何も。それは単に不必要であると考えられました。
habnabit 2010

@ジェレミーブラウン-確かに。良いメモ。
atzz

6
@thebackhand-ブロックを使用する言語では、スコープのforループは一般原則の自然な拡張です。Pythonでは、それは特別なケースでなければならず、特別なケースは、それらに説得力のある利点がない限り、回避されるべきです。
atzz

39

このための本当に便利なケースは、使用enumerateしていて、最後に合計数が必要な場合です。

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

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

注意すべきもう1つのこと:Python 2では、リスト内包の変数もリークされます。

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

ただし、Python 3には同じことが適用されません。


4
あなたはおそらくelse節でそれをしたかもしれません、すなわち。else: print "I did something {0} times".format(count)-ローカルスコープ(Pythonには存在しない)が消える前
Nas Banov

3
2番目の例だけがPython 3で機能しませんよね?最初はまだしますか?Python 3から削除された理由についてのメモ?
エンドリス2012

7
カウントの場合、enumerate(a、start = 1)の項目: #デフォルトのインデックスはゼロから
Tao Zhang

3
最初の例は、良い使用例というよりは、このスコープ規則が危険であり、信頼すべきではないという証拠に似ています。someiterator空の場合はどうなりますか?
最大

1
@Nas elseこの場合は句を使用できますが、ループ本体がbreak時期尚早になる可能性があるため、一般的には機能しません。
jamesdlin 16

2

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


1

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


-1

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

現在の状況では:

# 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

これは0total代入後のループの内側がループのtotal外側と同じ変数ではないためです。これは最適な動作または期待される動作ではありません。


5
質問に答えません。OPは、合計(または例ではbar)ではなく、fooについて尋ねていました。
James Bradbury

6
@JamesBradbury totalとはfooまだOPのシナリオでループローカルな束縛を持っているでしょうし、ロジックは同じです。
Kirk Strauser 2013年

2
OP:「 'bar'がループの外でアクセス可能である必要がある理由を理解できます(そうでなければ、forループの機能は非常に制限されます。)理解できないのは、制御変数を維持する必要がある理由です。ループが終了した後のスコープ内。」(強調鉱山)
James Bradbury

2
@JamesBradburyあなたは正しいかもしれませんが、3年前にこれに答えたので、今は議論する価値はないでしょう。
Kirk Strauser 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.