結局 for i in range() ってなに?
はじめに
こんにちは、高校部長です。
python歴だいたい3ヶ月の初心者です。
さて、2023の3月に今年度から新課程で新しく加わった情報Iの学期末テストを受けたのです。
そこで、以下のようなコードが:
for i in range(0, 6, 3):
i = i + 3
print(i)
僕はその時単純に
「なるほどな!じゃあこれをC++っぽく直すと、」
for(int i = 0; i < 6; i += 3){
i += 3;
std::cout << i << std::endl;
}
「になるから…2回目のループの初めではi
に6
が代入されているから実行されず、出力結果は3
だけに違いない!!」
と考えたのですよ。そしてなんと答えは
3
6
????????????
range
range
はPythonの組み込み型の一種らしい。
初期化は
range(stop)
range(start, stop[, step])
公式ドキュメント^1曰く、
step が正の場合、range r の内容は式 r[i] = start + step*i で決定されます。ここで、 i >= 0 かつ r[i] < stop です。
どうやらrange
はlist
のような挙動するらしい。試しにlist
型にキャストしてみると、
list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(0, 6, 3)) # [0, 3]
つまりfor i in range(0, 6, 3)
というのはfor i in [0,3]
と同じ挙動をするということだ。
for i in [0, 3]:
i = i + 3
print(i)
#3
#6
つまるところ処理の終わりでカウンタ変数i
に3がたされて、i
が0、もしくは3であった場合は処理を実行するということ?だと考えていたのだが、どうやらそうではないらしい…むしろそのように書きたいのならwhile
文で書くべきだし……
for ってなんだろう
公式ドキュメントからの引用^2:
for_stmt ::= "for" target_list "in" starred_list ":" suite
["else" ":" suite]
The starred_list expression is evaluated once;
An iterator is created for that iterable.
The first item provided by the iterator is then assigned to the target list
for ループはターゲットリスト内の変数への代入を行います。 これにより、for ループ内も含めて、それ以前の全ての代入は上書きされます:
for i in range(10):
print(i)
i = 5 # this will not affect the for-loop
# because i will be overwritten with the next
# index in the range
つまり、まずrange(0, 6, 3)
はfor
ループが始まるときに1度だけ評価されて、そのあとはイテレータである[0, 3]
が生成され、最初のi
にその最初の要素が代入されるという。
そしてsuite
の終わりにはi
に加算されるのではなく、次のイテレータの要素が代入される。つまり、
for i in range(0, 6, 3):
i = i + 3
print(i)
においては、一回目のループでi
に0
が代入されて3
が足されてそれを表示し、二回目のループでfor
によってi
に3
が代入されてそれに3
が足されて6
が表示されるということ。
なるほどなー。
まとめ
for
文はカウンタ変数にin
の後に記述したイテラブルなオブジェクトの要素を一つずつ代入する。カウンタ変数はループ内で値を代入しても、ループの始めでコレクションの次の要素が代入される。だからrange
の代わりにlist
型を入れてそれそれの要素を取り出すという芸当が可能になるのですね。
じゃあそれforeach
じゃねぇか!!!^3
さいごに
ラムダ式楽しい!!!