Programmierkurs
für Naturwissenschaftler/innen

繰り返し (ループ)

ここでは繰り返しについて説明する。

for ループ

何かを繰り返し実行したいことがよくある。

例えば、1 から 10 までの整数の三乗の和を求めたいとしよう。

summation = 1 ** 3 + 2 ** 3 + 3 ** 3 + 4 ** 3 + 5 ** 3 + 6 ** 3 + 7 ** 3 + 8 ** 3 + 9 ** 3 + 10 ** 3
print(summation)

と書けるが、間違いやすいし、1 から 100 までの場合を計算したい場合はさらに長くなり、間違いが混入する可能性が高くなる。 このような場合は for ループを使う (詳細は後で説明するので、今はざっと目を通してもらえれば良い)。

summation = 0             # 初期化を忘れないこと!

for i in range(1, 11):    # なぜ 11 なのかは後で説明する
    summation += i ** 3   # summation = summation + i ** 3 でもよい

print(summation)

これをフローチャートとして書くと次のようになる。

/images/loop-for-sum.png
for-loop

上のプログラムとフローチャートを見比べて、どことどこが対応しているか確認せよ。

「上から下へ」の流れ以外に、前に戻る流れがあるのが分かる。 すなわちこれも「制御構造」の一つである。 また、菱形が出てきていることからも分かるように、本質的には条件分岐であることも分かるだろう。

また、この練習問題で気付いたと思うが、Python の場合 $i \leftarrow i + 1$ 等の部分がプログラム中に陽にはあらわれないので少しとまどったかもしれない。 しかしここでは $i$ が 1 ずつ増えていく、というのが重要な点であるので、それを意識してもらいたい。

ひとまず、簡単な例で体感してみよう。

次のプログラムを入力して実行してみよ。 詳細はすぐに説明するが、何をやっているか想像してみよ。 (先に説明を読んで後で試してみてもよい)

for i in range(3):
    print(i)

実行結果

次のプログラムを入力して実行してみよ。 詳細はすぐに説明するが、何をやっているか想像してみよ。 (先に説明を読んで後で試してみてもよい)

summation = 0
for i in range(1, 6):
    summation += i
    print("  i =", i, ", summation =", summation)

print("Summation is", summation)

実行結果

for 文の構造

簡単な例で for 文の構造をきちんと見てみよう。

for i in range(3):
    print(i)

for 文は、

一行目

for 変数 in 反復対象 :

二行目以降

実際の処理

という構造になっている。

一行目の for, in 及び : はそのように書く (最後の : を忘れないこと)。 二行目以降に実際の処理を書く。関数のときと同様に、繰り返したい部分をインデント (字下げ) によって指示する。 この部分が繰り返し実行される。

in の後に書くものについてきちんと説明するのは簡単ではないので、この文書では、 range() (と後で説明する配列) が主に使われる、とだけ説明しておく。

for ループではこの range() の使い方が肝なので、以下でもう少し詳しく見てみよう。

range() とは

range() はざっくり言うと、数を順番に生成するものである。 例えば range(n) は 0, 1, …, n - 1 (n ではないので注意) という数を順番に生成する。 まだ分かりにくいであろうから、以下で具体例を見てみよう。

range() の使い方

range() は取る引数の数によって動作が若干異なる。

いずれの場合も引数は整数のみ与えることができる。 従って得られる値も常に整数である。

引数が一つの場合

range(n) は 0 から n 個の整数を生成する。 0 から n 未満 の数を生成する、とも言える。 つまり、 range(n) は 0, 1, …, n - 1 を生成する。

for i in range(3):
    print(i)

であれば、 range(3) は繰り返しのたびにそれぞれ 0, 1, 2 を生成するので、実行結果は、

0
1
2

となる。

引数が二つの場合

range(n, m) は n から m 未満 の整数を生成する。 (range(m)range(0, m) と等価である。)

for i in range(10, 13):
    print(i)

であれば 10, 11, 12 が表示される (13 が含まれていないことに注意)。

ひとまず上記二つを押さえておけば十分であろう。 もし余裕があれば、次も押さえておくと良い (使用する機会はあまり多くない)。

引数が三つの場合

range(n, m, s) は n から m 未満 の整数を s おきに生成する。

for i in range(1, 10, 3):
    print(i)

においては range(1, 10, 3) は 1 から 3 ずつ増やしていって 10 未満までの数を生成する、つまり 1, 4, 7 が表示される。

次のプログラムでは何が表示されるか考えてみよ。 その後、このプログラムを入力して実行してみよ。

for i in range(1, 3):
    print(i)

また、

  • 値を変えた場合、

  • 引数が 1 個の場合、

など range() の引数をいろいろ変えて試してみよ。

実行結果

range() についてもっと詳しく知りたければ、 https://docs.python.org/ja/3/library/stdtypes.html#ranges 等を参照せよ。

for 文を使って、1 から 100 までの整数の和を求めるプログラムを書け。

実行結果

while ループ

for は繰り返し回数が重要であったが、繰り返し回数が事前に分からず、ある条件を満たしている間は繰り返したい、という場合がある。

例えば、1 からの整数の三乗を足していったとき、最初に 1000 を越えるのはいつかを知りたいとしよう。 この場合、事前に繰り返し回数は分からないので、for では書きにくい。 その場合、 while を使って次のように書くことができる。

n = 0
summation = 0
while summation < 1000:
    n += 1
    summation += n ** 3
    print(n, summation)

print("Result:", n, summation)

上のプログラムを入力し、実行してみよ。 その際、それぞれの部分でなにをやっているか、想像してみよ。

実行結果

while 文の構造は次のようになっている。

while ループ条件:
    処理
/images/loop-while-python.png
while-loop

これは、まず「ループ条件」を評価し、これが真だったら「処理」の部分が実行される。 処理の部分は for などと同様に、インデントによって指示する。 まず条件が判定されるので、「処理」の部分が一度も実行されない場合がある。

  1. 次のプログラムを入力し、実行せよ。 何が起きたか、何故そうなったか考えてみよ。

    n = 50
    
    while n < 0:
        n -= 10
        print("in while:", n)
    
    print("result:", n)
  2. もしこのプログラムの意図が「 n から 10 を引いていって、 n の値が負になったら終了する」だった場合、 どこをどのように修正すれば良いか検討せよ。 実際に修正して、期待通りに動作するか確認せよ。 (この場合、最後に result: -10 と表示されるのが、期待される結果である。)

実行結果

break

ループを途中で抜けたいときには、 break を使うことができる。 ただし break の使用は可能なら避けるのが望ましい。 使う前に、本当に必要であるか、より良い書き方が無いか良く考えてから使用するようにしよう。 break は for でも while でも使用できる。

比較的良く使うパターンは次のものである。

ある繰り返し計算 (例えば ニュートン法 を用いた計算) をしていて、収束したら終了させたい場合、理論的には、

while not converged:    # converged には具体的な条件を書く
    # 計算

のように書ける。

しかし、収束するとは限らない場合 (大抵そうである)、最大の繰り返し回数を定めておいて、 その回数以内に収束しなかったら諦めるようにしたいということが良くある。 そのような場合、例えば、

maxloop = 100

for i in range(maxloop):
    # 計算

    if converged:    # converged には具体的な条件を書く
        break

あるいは、

maxloop = 100
count = 0

while not converged:    # converged には具体的な条件を書く
    # 計算

    count += 1
    if count >= maxloop:
        print("not converged")
        break

などと書ける。 これは、回数制限付き (ここでは 100 回) の while ループと見ることができる。

なお、入れ子の for/while (ループの中のループ) で break を使用した場合は、その break から見て 最も内側の ループを抜ける。

ループでの注意

ループを書く際には、終了条件に十分注意しよう。 ループが一回多かったり、あるいは一回少なかったりするのはよくあるミスである。 このようなミスはかなり見つけにくいことが多い。

また、 while で常に成立する (絶対に不成立にならない) 条件を書くとループが終わらない無限ループとなる。

まとめ

ここでは、繰り返しの方法の基礎について学んだ。

  • 繰り返しの為には for, while が使える

  • 中断したい場合には break を使う (ただし、慎重に使うべきである)

  • for で良く使われる range() について説明した