タートルグラフィックスで学ぶ Python のキホン 第 6 章
教材コード
第 6 章

繰り返す

同じ命令を何度も書かない.「何回」だけを伝えます.

第 2 章で正十角形を描いたとき,fd(40)rt(36) を 10 回ずつ,合わせて 20 行書きました.書いているうちに 「これは人間のやる仕事ではない」と思ったはずです.その感覚が正しいのです.

同じことを何度も繰り返すのは,コンピュータが一番得意な仕事です. 人間は「何を何回するか」だけを書けばよい.今回はそのための書き方, 繰り返し(ループ)を習います.今日を境に,プログラムの長さと 絵の複雑さは関係がなくなります.

この章でできるようになること
  • forrange を使って,同じ命令の繰り返しを短く書ける
  • コロンと字下げで,どこからどこまでが繰り返しの中かを指定できる
  • range(n)range(a, b)range(a, b, step) を使い分けられる
  • 繰り返しの流れ図(フローチャート)が読め,それをプログラムに写せる
  • ループ変数 i を使って,1 回ごとに少しずつ違う図形が描ける
  • 正 n 角形や円を,回数と角度の計算から描ける
  • 字下げの間違いで起きるエラーを読んで,自分で直せる
  • 繰り返しの中に if を書いて,あるときだけ違うことをさせられる
  • count = count + 1total = total + i(自己代入)で,数を数える・合計を求めることができる
読み方 今回も右側のコード欄で実行しながら読み進めてください. 繰り返しは目で見ると一瞬で分かるのに,文字だけ読んでいると 分かりにくいところです.速さを「ゆっくり」にして,かめが同じ動きを 何度もなぞる様子を眺めるのが,いちばんの近道です.

6.1 同じことを何度も書いている

6.1.1 どこが同じかを探す

繰り返しの書き方を習う前に,まず「何を繰り返すのか」を見つける練習をします. 第 2 章で書いた家のプログラムを,もう一度見てください.

第 2 章の house.py
from turtle import *

# 屋根を描く
lt(60)
fd(100)
rt(120)
fd(100)
rt(120)
fd(100)

# 本体(かべ)を描く
lt(90)
fd(100)
lt(90)
fd(100)
lt(90)
fd(100)
lt(90)
fd(100)

done()

同じことを書いている場所が2 か所あります.どこでしょうか.

  • 屋根では fd(100)rt(120) の組が 3 回
  • かべでは lt(90)fd(100) の組が 4 回
繰り返しの見つけ方 繰り返しを見つけるコツは,「同じ数が何度も出てくる場所」を探すことです. 100120 が縦に並んでいたら,そこはほぼ確実に繰り返しです.

6.1.2 繰り返しで書き直す

見つけた繰り返しを,今日習う for で書き直したものが次です. 描かれる絵はまったく同じで,行数だけが減っています.

house_for.py
from turtle import *

# 屋根を描く(fd と rt を 3 回)
lt(60)
for i in range(3):
    fd(100)
    rt(120)

# かべを描く向きへ
rt(150)

# かべを描く(fd と lt を 4 回)
for i in range(4):
    fd(100)
    lt(90)

done()
図 6.1 家.第 2 章とまったく同じ絵が,短いプログラムで描ける.

fdrt が並んでいた部分が, 「中身を 1 組だけ書いて,回数を添える」形になりました. これが今回いちばん大事な発想です.

6.1.3 正十角形を 3 行にする

第 2 章の虫食いで,fd(40)rt(36) を 10 回ずつ 書かされたのを覚えているでしょうか.あの 20 行は,次の 3 行と同じ意味です.

decagon.py
from turtle import *

pensize(2)
pencolor("indigo")

for i in range(10):
    fd(40)
    rt(36)

done()
図 6.2 正十角形.20 行が 3 行になった.
やってみよう ここで 1036 に,rt(36)rt(10) に変えてみてください.正三十六角形になります. 手書きなら 72 行の作業が,2 か所の数字を直すだけで済みます.

6.2 for の書き方

6.2.1 形を覚える

繰り返しの書き方は次のとおりです.1 文字も省略できません.

for のかたち
for i in range(4):
    fd(100)
    lt(90)
部分意味
for「繰り返すぞ」という合図.必ず小文字で書く
iループ変数.今何回目かを覚えておく変数.名前は自分で決められるが,特に理由がなければ i を使う
in range(4)i に入れる数の並びを作る.range(4) なら 0, 1, 2, 3 の 4 個
:(コロン)行の終わりに必ず付ける.「ここから中身です」の意味.忘れると SyntaxError
字下げした行繰り返される中身.半角スペース 4 つ下げるのが決まり

上の 3 行は,次の 8 行とまったく同じ意味です.

同じ意味の 8 行
fd(100)
lt(90)
fd(100)
lt(90)
fd(100)
lt(90)
fd(100)
lt(90)
はじめのうちに必ずやる 2 つの間違い コロンを忘れると SyntaxError: expected ':', 字下げを忘れると IndentationError: expected an indented block が出ます. どちらも「for の行の最後にコロン,次の行から字下げ」を 覚えていれば起きません.

6.2.2 どこまでが繰り返しの中か

Python では,字下げしてある行だけが繰り返されます. 字下げをやめた行から先は,繰り返しが全部終わってから 1 回だけ実行されます. 次の 2 つを見比べてください.違いは fd(120) の行の 字下げだけです.

図 6.3 外に書いた場合.赤い線は 1 本だけ
図 6.4 中に書いた場合.赤い線が 3 本

左は正三角形を描いてから赤い線を 1 本引きます. 右は三角形の 1 辺を描くたびに赤い線を引くので,形が変わります. 字下げは見た目を整えるためのものではなく,意味そのものです.

scope.py
from turtle import *

pensize(2)

for i in range(3):
    fd(80)
    lt(120)

pencolor("crimson")
fd(120)      # ← 字下げしていない.繰り返しが終わってから 1 回だけ

done()
図 6.5 繰り返しの外に書いた命令は,最後に 1 回だけ実行される.
字下げの幅 字下げは半角スペース 4 つに統一してください. コード欄で Tab キーを押すと 4 つ分の空白が入ります. 途中で 2 つにしたり 8 つにしたりすると,エラーになったり, 思っていないところまで繰り返されたりします.
虫食い虫食い 6-A 正六角形

1 辺 60 の正六角形for で描きます. 2 つの ____ を埋めてください. 角の数は 6,曲がる角度は 360 ÷ 6 でしたね.

fill4a_hexagon.py
from turtle import *

pensize(2)
pencolor("seagreen")

for i in range(____):
    fd(60)
    rt(____)

done()

6.3 流れ図で見る繰り返し

第 5 章で,if の流れを絵にした 流れ図(フローチャート)を見ました(第 5 章 5.1.3 節). 繰り返しも,同じ記号で絵にできます. ちがうのは,もと来たところへぐるっと戻る矢印が付くことだけです.

流れ図は,書く前に使う道具です 流れ図は,きれいに清書するためのものではありません. プログラムを書く前に,頭の中を整理するための道具です. ノートのすみでも,紙の裏でもかまいません. 「まず何をして,どこで何を調べて,どこへ戻るのか」を先に絵にしておくと, そのあとに書く Python は,それを書き写すだけになります. 第 17 章「並び替え」で,自分で手順を考えるときに,またこの道具を使います.

6.3.1 流れ図の記号

使う記号は 4 つだけです.第 5 章と同じものです.

記号名前何を表すか
角丸の四角端子はじめ・おわり
長方形処理実際にやること(fd(100),値を入れる,など)
ひし形判断条件を調べるところ.はいいいえで道が分かれる
矢印流れ次にどこへ行くか.上に戻る矢印があれば繰り返し

6.3.2 for の流れ図

for i in range(4): を流れ図にすると,次のようになります.

はじめi を 0 にするi は 4 より小さいかはいいいえ繰り返す中身を実行する(fd(100) lt(90))i に 1 を足す戻るおわり
図 6.6 for i in range(4): の流れ図.中身を実行したら,判断のところへ戻る.

上から順に読んでみてください.やっていることは 4 つです.

  • i を 0 にする(はじめの値を決める)
  • i はまだ 4 より小さいかと調べる(まだ残っているか)
  • ③ 小さければ中身を実行する
  • i に 1 を足して,②へ戻る

②へ戻るたびに i は 1 ずつ大きくなり, 0 → 1 → 2 → 3 と進みます. i4 になったところで 「4 より小さいか」がいいえになり,繰り返しが終わります. 中身が実行されたのは,ちょうど 4 回です.

書いていないのに,やってくれている この図を for の 3 行と見くらべてください. プログラムに書いてあるのは,「4 回」と「中身」だけです. ①②④は書いていません.それでも動くのは, forrange代わりにやってくれているからです.

6.3.3 while の流れ図

繰り返しにはもう一つ while という書き方があります (くわしくは 6.8 節で習います). while「条件が成り立つ間くり返す」という書き方で, 流れ図にすると,for よりも素直な形になります.

while のかたち
while 条件式:
    繰り返す中身
はじめ条件式はいいいえ繰り返す中身を実行する戻るおわり条件を先に調べます.はじめから成り立たなければ,中身は 1 回も実行されません.
図 6.7 while 条件式: の流れ図.条件を調べてから中身へ進む.

ここで大事なのは,判断がいちばん先に来ていることです. 中身へ進む前に,かならず条件を調べます. ですから,はじめから条件が成り立たなければ,中身は 1 回も実行されません

0 回ということもある i = 10 の状態で while i < 4: と書くと, いちばん最初の判断でいいえになり, 中身を素通りして,すぐ次の行へ進みます. 「少なくとも 1 回は実行される」と思いこまないでください. 流れ図を見れば,それが一目で分かります.

6.3.4 forwhile を見くらべる

同じ「4 回くり返す」を,forwhile で書いたときの 流れ図を並べてみます.形はまったく同じです.

for i in range(4):while i < 4:i を 0 にするi は 4 より小さいかfd(100)lt(90)i に 1 を足すi = 0i < 4fd(100)lt(90)i = i + 1はじめの値続ける条件繰り返す中身1 増やす点線の 3 つは for が引き受けてくれます.自分で書くのは,青い「中身」だけです.
図 6.8 forwhile の対応.点線の 3 つは for が引き受けてくれる.

while で書くと,はじめの値・続ける条件・1 増やす,の 3 つを自分で書くことになります. そのぶん,書き忘れる場所も 3 つあります. とくに「1 増やす」を書き忘れると,条件が永遠に成り立って終わりません

ふだんは for でよい 回数が決まっているなら,迷わず for を使ってくださいwhile は「何回で終わるか,書く前には分からない」ときのための書き方です. この教材では while True:(ずっと繰り返す)は使いません (理由は 6.8.2 節にあります).
虫食い虫食い 6-B 流れ図をプログラムに写す

図 6.8 の右側,while のほうの流れ図を, そのままプログラムに写します. ____ は 3 か所です.

  1. はじめの値 … i をいくつから始めますか.
  2. 続ける条件 … i が 4 より小さい間です.
  3. 増やす数 … 1 回ごとにいくつ増やしますか.
ヒント 正しく埋められれば,1 辺 100 の正方形が描かれます. うまくいったら,3 か所の数を変えて,何が起きるか試してみてください. 増やす数を 0 にしてはいけません.終わらなくなります.
fill4b_flow.py
from turtle import *

pensize(2)
pencolor("teal")

i = ____                # ① はじめの値

while i ____ 4:         # ② 続ける条件
    fd(100)
    lt(90)
    i = i + ____        # ③ 1 回ごとに増やす

done()

同じ絵を for で描くと for i in range(4): の 3 行で済みます. 流れ図は同じなのに,書く量がちがう. これが for のありがたみです.

6.4 range で「何回」を決める

6.4.1 range(n) は 0 から始まる

range(5) が作るのは 0, 1, 2, 3, 4 です. 0 から始まり,5 は入りません.個数はちょうど 5 個です. 本当にそうなっているか,print で確かめましょう.

range_print.py
for i in range(5):
    print(i)

print("おしまい")

コンソールに 0 1 2 3 4 が縦に並び,最後に おしまい と出ます.print(i) は字下げの中にあるので 5 回実行され,print("おしまい") は外にあるので 1 回だけです.

0 から数える 「0 から始まって,最後の数は入らない」は,プログラミングでは ほぼ全ての言語に共通する決まりです. 最初は必ず1 個ずれます(これを off-by-one エラーといいます). 迷ったら print(i) を 1 行入れて,実際の値を見るのが確実です.

6.4.2 range の 3 つの書き方

書き方作られる数個数
range(5)0, 1, 2, 3, 45 個
range(1, 6)1, 2, 3, 4, 55 個
range(0, 10, 2)0, 2, 4, 6, 85 個
range(20, 160, 20)20, 40, 60, 80, 100, 120, 1407 個
range(10, 0, -1)10, 9, 8, …, 110 個

3 つめの数は「いくつ飛ばしか」を表し,step といいます. マイナスにすると減っていきます.どの書き方でも 終わりの数そのものは入らないことに注意してください.

range_step.py
from turtle import *

pensize(2)
pencolor("darkcyan")

# 20, 40, 60, … 140 と長くなる
for i in range(20, 160, 20):
    print(i)
    fd(i)
    rt(90)

done()
図 6.9 1 辺ずつ長くなる四角い渦巻き.
虫食い虫食い 6-C range の数を決める

上のプログラムと同じ形です.20 から 140 まで 20 ずつ長くするには, range に何と何を書けばよいでしょうか. ____ を 2 つ埋めてください. 終わりの数は入らないことを思い出してください.

fill4b_range.py
from turtle import *

pensize(2)
pencolor("darkcyan")

for i in range(____, ____, 20):
    fd(i)
    rt(90)

done()

6.4.3 ループ変数は使わなくてもよい

for i in range(10): と書いても,中で i を使わなくてもかまいません. その場合,i「回数を数えるためだけの変数」になります. 正十角形のプログラムがまさにそれでした.

ヒント 使わない変数に名前を付けるのが気持ち悪い人は,for _ in range(10): のように _(アンダースコア)を使う書き方もあります. この教材ではどちらでもかまいません.

6.4.4 逆に数える — step を負にする

3 つめの数(step)は負の数でもかまいません. そのときは,大きいほうから小さいほうへ減りながら繰り返します. ロケットの発射カウントダウンのように,逆向きに数えたいときに使います.

countdown.py
# 10 から 1 まで,1 ずつ減らす
for i in range(10, 0, -1):
    print(i)

print("発射!")

# 10 から 2 まで,2 ずつ減らす
for i in range(10, 0, -2):
    print(i)
ここでも「終わりは入らない」 負の step でも,終わりの数そのものは入りませんrange(10, 0, -1) が作るのは 10, 9, …, 1 で,0 は出ません. 0 まで欲しいときは range(10, -1, -1) と書きます. ここでも 1 個ずれやすいので,print(i) で確かめる習慣をつけてください.
タートルで使うと この値をそのまま fd に渡せば,だんだん短くなる図形になります. 図 6.9 の渦は内から外へ伸びていきましたが, for i in range(140, 20, -20): に書き換えると, 今度は外から内へ巻き込む渦になります.試してみてください.

6.5 繰り返しの中でループ変数を使う

ここからが繰り返しの本当の力です.i は 1 回ごとに値が変わるので, それを fdrt の中に書くと, 毎回少しずつ違う動きをさせられます.

6.5.1 だんだん長くなる渦巻き

spiral.py
from turtle import *

pensize(2)
pencolor("purple")

for i in range(60):
    fd(i * 3)    # i は 0, 1, 2 … と増えるので,線がだんだん長くなる
    rt(91)       # 90 ではなく 91 にすると,少しずつずれて渦になる

ht()
done()
図 6.10 渦巻き.rt(90) にすると正方形に戻る.

fd(i * 3)3 や,rt(91)91 をいろいろ変えてみてください. rt(90) にするとぴったり重なって正方形になり, rt(120) にすると三角の渦になります.

虫食い虫食い 6-D 渦巻きを作る

渦巻きを描きます.i 回目の線の長さを i の 3 倍にしてください. ____ に入るのは数ではなく, i を使ったです.

fill4c_spiral.py
from turtle import *

pensize(2)
pencolor("purple")

for i in range(60):
    fd(____)
    rt(91)

ht()
done()

6.5.2 円を描く

第 2 章で「円の正体は正 72 角形」と書きました. 繰り返しを使えば,円は 3 行です.fd(1)rt(1)360 回繰り返すと,1 度ずつ 360 度まわって 1 周します.

circle.py
from turtle import *

pensize(2)
pencolor("royalblue")

for i in range(360):
    fd(1)
    rt(1)

done()
図 6.11 円.1 歩進んで 1 度曲がるのを 360 回.

6.5.3 円の大きさは何で決まるか

fd の数(1 回に進む長さ)と rt の数(1 回に曲がる角度)を 変えると,円の大きさが変わります.ただし 「1 周ぶん回る」という条件は守らなければなりません. 角度を rt(5) にしたら,繰り返す回数は 360 ÷ 5 = 72 回です.

図 6.12 fd(2)rt(5) を 72 回
図 6.13 fd(6) にすると 3 倍の大きさ
図 6.14 rt(15)・24 回.角ばって見える
  • 1 周するには (曲がる角度)×(回数)= 360 になっていること.
  • 円の周の長さは (進む長さ)×(回数).これが大きいほど大きな円になる.
  • 角度を大きく,回数を少なくすると,角ばって多角形に見える
虫食い虫食い 6-E 5 度ずつの円

fd(6)rt(5) の組で円を描きます. ちょうど 1 周するには何回繰り返せばよいでしょうか. ____ を埋めてください.

fill4d_circle.py
from turtle import *

pensize(2)
pencolor("crimson")

for i in range(____):
    fd(6)
    rt(5)

done()

6.6 for と図形は相性がよい

6.6.1 正 n 角形を n から描く

第 3 章で習った変数と組み合わせると,角の数を 1 か所変えるだけで どんな正多角形にもなるプログラムが書けます.曲がる角度は 360 / n です.

ngon.py
from turtle import *

n = 12          # ← ここだけ変える
length = 40

pensize(2)
pencolor("teal")

for i in range(n):
    fd(length)
    rt(360 / n)

done()
図 6.15 n = 12 のとき.正十二角形になる.

n を 3 にすれば正三角形,5 にすれば正五角形, 50 にすればほとんど円になります.プログラムは 1 文字も変えません. これが「変数」と「繰り返し」を組み合わせたときの強さです.

割り切れないときは 360 / n は,n が 7 のときに 51.42857142857143 のような小数になります. かめは小数の角度でもきちんと曲がるので,そのままで問題ありません. 整数にしたいときは 360 // n と書きますが, 誤差が積もって図形が閉じなくなるので,ここでは / を使ってください.
虫食い虫食い 6-F 正九角形

n の値を使って正 n 角形を描きます. ____ を 2 つとも n を使った形で埋めてください. 数字をそのまま書いてしまうと,n を変えたときに形が崩れます.

fill4e_ngon.py
from turtle import *

n = 9

pensize(2)
pencolor("darkorange")

for i in range(____):
    fd(50)
    rt(360 / ____)

done()

6.6.2 星・アスタリスク

第 2 章で 10 行かけて書いた星も,繰り返しなら 3 行です. とげのような図形(アスタリスク)も, 「進んで戻って少し回る」を繰り返すだけで描けます.

図 6.16 星.rt(144) を 5 回
図 6.17 アスタリスク.進んで戻って回る
asterisk.py
from turtle import *

pensize(2)
pencolor("orangered")

for i in range(8):
    fd(60)
    bk(60)
    rt(45)

done()
図 6.18 8 本のとげ.360 ÷ 8 = 45 度ずつ回っている.
ヒント とげの本数を 12 本にするには,range(8)range(12) に, rt(45)rt(30) に変えます(360 ÷ 12 = 30). 回数と角度はいつも一緒に変えると覚えてください.

6.7 字下げを間違えるとどうなるか

繰り返しでいちばん多い失敗は,命令の書き間違いではなく 字下げです.わざと間違えて,何が起きるかを先に見ておきましょう.

6.7.1 字下げが無い(IndentationError)

err_indent.py
from turtle import *

for i in range(4):
fd(100)
lt(90)

done()

IndentationError: expected an indented block と出ます. 「字下げされたかたまりが来るはずなのに,来なかった」という意味です. for の行でコロンを書いた以上, 次の行は必ず字下げしなければなりません.

6.7.2 字下げを忘れて 1 回しか実行されない

もっと厄介なのは,エラーにならない間違いです. 次のプログラムは正方形を描くつもりですが, lt(90) の字下げが足りません.

err_scope.py
from turtle import *

pensize(2)
pencolor("crimson")

pu()
goto(-200, 0)
pd()

for i in range(4):
    fd(100)
lt(90)          # ← 字下げしていない!

done()
図 6.19 まっすぐ 400 進んでから 1 回だけ曲がる.正方形にならない.

fd(100) だけが 4 回繰り返され,lt(90)全部終わってから 1 回だけ実行されます. 結果は長さ 400 の直線です.エラーは出ませんが,まったく別のプログラムになっています.

いちばん多いバグ エラーが出ないからといって正しいとは限りません. 形がおかしいときは,まず字下げの列をそろえて見ること. コード欄では,同じ深さの行の左端がきれいにそろっているかを目で確かめてください.

6.7.3 字下げの幅がそろっていない

やってはいけない例
for i in range(4):
    fd(100)
  lt(90)        ← 4 つと 2 つが混ざっている

これは IndentationError: unindent does not match any outer indentation level になります.「その字下げの深さは,どのかたまりにも当てはまらない」という意味です. 同じかたまりの中は,すべて同じ幅で字下げしてください.

繰り返しでよくある 6 つ
症状原因と直し方
SyntaxError: expected ':'for の行の最後にコロンが無い
IndentationError: expected an indented blockfor の次の行を字下げしていない
IndentationError: unexpected indent字下げの必要がない行を字下げしている
IndentationError: unindent does not match …字下げの幅が行によって違う.半角スペース 4 つにそろえる
NameError: name 'i' is not defined繰り返しのi を使おうとしている
エラーは出ないが形が変字下げの深さが思っているものと違う.6.7.2 の例を見直す

6.8 while — 回数が決まっていない繰り返し

6.8.1 条件が成り立つ間くり返す

繰り返しにはもう一つ while という書き方があります. for「何回」を決めるのに対し, while「どうなるまで」を決めます. 第 5 章の if で習った条件式が,そのまま使えます.

while のかたち
while 条件式:
    繰り返す中身

条件式が成り立っている間,中身が繰り返されます. 1 回終わるたびに条件式をもう一度調べ,成り立たなくなったところで終わります.

while_spiral.py
from turtle import *

pensize(2)
pencolor("seagreen")

length = 10

while length < 150:
    fd(length)
    rt(90)
    length = length + 10    # ← これを忘れると終わらない

done()
図 6.20 長さが 150 になるまで伸びつづける四角い渦.
条件を変える行を必ず入れる length = length + 10 は, 「今の length に 10 を足したものを,あらためて length に入れる」 という意味です.この行を書き忘れると条件が永遠に成り立ち, 繰り返しが終わりません.while を使うときの最大の注意点です.

6.8.2 ブラウザでは while True が使えない

while True: は書かないこと 旧来の教材では,円を描き続けるために while True:(ずっと繰り返す) と書くことがありました.この教材では使えません. ブラウザの中で Python が動いているため,終わらない繰り返しに入ると 画面が固まって,実行を止められなくなります
  • この教材の実行環境は,描画命令が 12 万個を超えるか,実行が 10 秒を超えると自動的に止めて「無限ループになっていませんか」と知らせます.
  • 繰り返す回数が決まっているなら,迷わず for を使ってください.
  • 「キーが押されるまで動き続ける」「ずっとアニメーションする」ような処理は,第 10 章で習う ontimer で書きます.while True: ではありません.

この教材では,基本的に for を使いますwhile は「終わる条件がはっきりしている」ときだけに使ってください.

6.9 繰り返しの中で条件を使う

前の章習った if と,今回習った for は, 組み合わせて使えます.しかも,組み合わせたときにいちばん力を発揮します. 「繰り返しながら,あるときだけ違うことをする」 「繰り返しながら,数を数える・足していく」. この 2 つの型を覚えると,書けるプログラムの幅が一気に広がります.

6.9.1 ループの中に if を書く

for の中に if を書くと,字下げは2 段になります. if繰り返しの 1 回ごとに調べられるので, 「1 回目は成立,2 回目は不成立」というように,回ごとに違う動きをします.

loop_if.py
from turtle import *

pensize(3)

for i in range(18):
    length = i * 12            # 0, 12, 24 … とだんだん長くなる

    if length > 100:           # 長さが 100 を超えた線だけ
        pencolor("crimson")
    else:
        pencolor("royalblue")

    fd(length)
    bk(length)
    rt(20)

ht()
done()
図 6.21 18 本の線を放射状に引き,100 を超えた線だけ赤にした.

length は 1 回ごとに変わるので, if length > 100: の答えも 1 回ごとに変わります. 短い線が青,長い線が赤になり,どこで色が変わったかが目で見て分かります. 10050150 に変えて,境目が動くのを確かめてください.

  • for の中身は4 つ字下げ
  • その中の if の中身は,さらに 4 つ足して8 つ字下げ
  • fdbkif の外(4 つ字下げ)なので,毎回かならず実行されます
字下げを 1 段まちがえると fd(length) の行をうっかり 8 つ字下げすると, 長い線しか引かれなくなります. エラーは出ません.出るのは「思っていたのと違う絵」だけです. 思った絵にならないときは,行の左端を縦に見てそろっているか確かめてください.

なお,if繰り返しの外に書いたほうがよいこともあります. 次は「kind が 1 なら * を,そうでなければ $ を 5 個並べる」 プログラムです.

pick.py
kind = 1              # ← 2 に変えて,もう一度実行してみる

if kind == 1:         # 何を並べるかを,先に 1 回だけ決める
    mark = "*"
else:
    mark = "$"

for i in range(5):    # 並べるのは 5 回
    print(mark)
どちらに if を置くか if の枝それぞれに for を書く,という書き方もできますが, その場合はほとんど同じ繰り返しを 2 か所に書くことになります. 変わるところ(記号)だけを if で決め, 変わらないところ(5 回並べる)は 1 回だけ書く. これが,同じことを 2 度書かないための考え方です.

6.9.2 数を数える — 自己代入

「赤くした線は何本あったか」を知りたくなりました. こういうときは,数えるための変数を 1 つ用意します. 第 3 章で習った x = x + 1 という書き方, つまり自己代入の出番です.

  1. 繰り返しに入る前にcount = 0 と置く.
  2. 数えたい場面に来るたびに count = count + 1 で 1 増やす.
  3. 繰り返しが終わってからcount を表示する.
count.py
from turtle import *

pensize(3)

count = 0                      # ← 数える前に 0 にしておく

for i in range(18):
    length = i * 12

    if length > 100:
        pencolor("crimson")
        count = count + 1      # ← 赤くしたので 1 増やす
    else:
        pencolor("royalblue")

    fd(length)
    bk(length)
    rt(20)

print("赤い線は", count, "本でした")     # ← 繰り返しの外で 1 回だけ

ht()
done()

絵は図 6.21 とまったく同じです.違うのは,コンソールに 赤い線は 9 本でした と出るところだけです. count = count + 1 は,算数の式としては成り立ちませんが, = は「右を計算して左に入れる」命令でしたから, 「今の count に 1 を足したものを,あらためて count に入れる」と読みます.

何回目lengthlength > 100この行のあとの count
0 回目0不成立0
0
8 回目96不成立0
9 回目108成立1
10 回目120成立2
17 回目204成立9
+= という書き方 count = count + 1count += 1 とも書けます. +=累算代入演算子といい, -=*=/= も同じように使えます. プロのプログラムではほとんど += が使われますが, 慣れるまでは count = count + 1 と書いて, 右を計算してから左に入れるという流れを意識してください.
0 にするのは繰り返しの前 count = 0繰り返しの中に書いてしまうと, 毎回 0 に戻されるので,最後はいつでも 0 か 1 にしかなりません. 数える箱は,繰り返しに入る前に 1 回だけ用意します.

6.9.3 合計を求める

数える代わりに足していけば,合計が求められます. 「1 から 10 までの合計」を,1 行も足し算を書かずに計算してみましょう.

total.py
total = 0                      # ← 足す前は 0

for i in range(1, 11):         # i は 1, 2, 3 … 10
    total = total + i          # 今までの合計に i を足す
    print(i, "を足した →", total)

print("1 から 10 までの合計は", total)

コンソールに 1 3 6 10 15 21 28 36 45 55 と, 合計がふくらんでいく様子が出ます.最後は 55 です. range(1, 11)11 は, 10 まで欲しいから 1 つ多く書いているのでした.

range の書き方を変えれば,足す相手も自由に変えられます. += を使って短く書いてみます.

total2.py
# 1 から 99 までの奇数(1, 3, 5, … 99)の合計
total = 0
for i in range(1, 100, 2):
    total += i
print("奇数の合計は", total)

# 10 から 2 まで,2 ずつ減らしながら足す(10 + 8 + 6 + 4 + 2)
total = 0
for i in range(10, 0, -2):
    total += i
print("逆に数えた合計は", total)
覚えるのは形だけ 「0 にしておく → 繰り返しの中で足す → 終わってから表示する」. この 3 つの形は,数を数えるときも,合計を求めるときも, このあと習う平均・最大値・最小値でも,まったく同じです. 型として覚えてしまってください.

6.9.4 見つかったかどうかを覚えておく

「繰り返しの途中で 1 回でも条件が成立したか」を, あとから知りたいことがあります. このときは TrueFalse を入れておく変数を使います. こういう変数をフラグ(旗)といいます.

  1. 繰り返しに入る前に found = False(まだ見つかっていない)と置く.
  2. 見つけたら found = True書き換える
  3. 繰り返しが終わってから foundif で調べる.
flag.py
num = int(input("2 以上の整数を入力してください > "))

found = False                       # まだ見つかっていない

for d in range(2, num):             # 2 から num - 1 まで
    if num % d == 0:                # 割り切れたら
        print(num, "は", d, "で割り切れます")
        found = True                # 見つけたことを覚えておく

if found:
    print("割り切れる数がありました")
else:
    print(num, "は 1 と自分自身でしか割り切れません")

コンソールの入力行を 12 から 13 に変えて, もう一度実行してみてください.今度は 1 行も「割り切れます」と出ず, 最後の行だけが出ます. 13 のように,1 と自分自身でしか割り切れない数を素数といいます. つまりこのプログラムは,素数かどうかを判定しているのです.

if found: という書き方 if found:if found == True: と同じ意味です. found の中身がもともと TrueFalse なので, わざわざ == True と比べなくてもよい,というわけです. どちらで書いてもかまいません.
旗は必ず先に立てておく found = False を書き忘れると,繰り返しの中で 1 度も成立しなかったとき, found という変数が存在しないまま 最後の if にたどりつき,NameError になります. 第 5 章で習った,「先に初期値を入れておく」という話とまったく同じです.
虫食い虫食い 6-G 3 から 7 までの合計

3, 4, 5, 6, 7 をぜんぶ足した合計を求めます. ____ を 4 つ埋めてください. 答えは 25 になるはずです. 終わりの数は入らないことを思い出してください.

fill4g_total.py
total = ____          # 足す前の合計

for i in range(____, ____):
    total ____ i      # 今までの合計に i を足す

print("合計は", total)

6.10 この章で出てきた書き方

書き方意味
for i in range(n):中身を n 回繰り返す.i は 0 から n−1
range(a, b)a から b−1 まで.b は入らない
range(a, b, step)a から b−1 まで step 飛ばし.step は負でもよい
:(コロン)forwhile の行の最後に必ず付ける
字下げ(半角 4 つ)繰り返す中身の範囲を表す.そろえること
fd(i * 3)ループ変数を式の中で使い,1 回ごとに変える
rt(360 / n)正 n 角形の外角.角の数から角度を計算する
while 条件式:条件が成り立つ間くり返す.終わる条件を必ず作る
range(10, 0, -1)逆向きに数える.step を負にすると減っていく
for の中の if繰り返しの 1 回ごとに条件を調べる.字下げは 2 段になる
count = count + 1自己代入.数を数える.count += 1 と同じ
total = total + i合計を求める.total += i と同じ
found = FalseTrueフラグ.「1 回でも成立したか」を覚えておく
print(i)ループ変数の値を確かめる.デバッグの基本

演習

「▶ この演習を開く」で右側に読み込み,それを発展させて作品にしてください. できあがったら「⤓ 保存」でファイルに保存して,手元に残しておきましょう. どの演習も,繰り返しを必ず使うことが条件です.

今回からの約束 第 2 章の演習では「行数を恐れないでください」と書きました. 今回からは逆です.同じ行が 3 回以上並んでいたら,繰り返しに直せないか考えてください.
演習演習 6-1 円のアレンジ

繰り返しで円を描くプログラムを与えます.これをもとに, 大きさや色の違う円を 3 つ以上組み合わせた絵を作ってください. 雪だるま,信号機,オリンピックの輪,水面の波紋 — 何でもかまいません. 位置をずらすには pu()goto() を使います.

出発点の円
演習演習 6-2 円の大きさを調べる

1 回に進む長さと曲がる角度を変えると,円の大きさがどう変わるかを実験します. 出発点のプログラムは,stepangle を変えるだけで いつもちょうど 1 周するようになっています.

  1. step を 1・2・4・8 と変えて実行し,大きさの変化を見る.
  2. angle を 1・5・15・30 と変えて実行し,形の変化を見る.
  3. 思ったとおりの大きさの円を描くにはどうすればよいかを,プログラムの先頭にコメントで 2〜3 行にまとめる.
ヒント // は「割り算の商(整数)」を求める記号です. 360 // 7 は 51 になります. angle は 360 を割り切れる数(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, …) にすると,きれいに 1 周します.
演習演習 6-3 四角形のアレンジ

繰り返しで正方形を描くプログラムを与えます.これをもとに, 正方形を並べる・重ねる・少しずつ回すなどして模様を作ってください. for の中の ifd の中で使うと, 大きさの違う正方形が簡単に描けます.

出発点の正方形
演習演習 6-4 正五角形のアレンジ

繰り返しで正五角形を描くプログラムを与えます. 大きさの違う正五角形を重ねる角の数を変えて別の正多角形にするなど,自由に発展させてください. 6.6 節のように n を変数にすると,一度にいろいろ試せます.

出発点の正五角形
演習演習 6-5 星のアレンジ

繰り返しで星を描くプログラムを与えます. 大きさや色の違う星を 3 つ以上並べて,夜空や旗の模様を作ってください. rt(144)rt(160) などに変えると, とがり方の違う星になります.

出発点の星
演習演習 6-6 アスタリスクのアレンジ

「進んで,戻って,少し回る」を繰り返してとげを描くプログラムを与えます. とげの本数・長さ・色を変えて,花火や雪の結晶のような図を作ってください. とげ 1 本を長くしたり短くしたりすると,形が大きく変わります.

出発点のアスタリスク(とげ 12 本)
自由演習 6-7 繰り返しで作品を描く

繰り返しを使って,好きな絵を描いてください. 同じ命令を手で何度も書いてはいけません. 繰り返せるところは必ず for にしてください.

  • for2 か所以上使うこと
  • ループ変数 ifdrt の中で1 回は使うこと(毎回少しずつ変える)
  • 色(pencolor)と太さ(pensize)を使うこと
  • 先頭にコメントで,題名・氏名・日付を書くこと
  • 仕上げに ht() を入れると作品らしくなる
ヒント ネタに困ったら,渦巻き(6.5.1)の角度を少しずつ変える, 正多角形(6.6.1)を少しずつ回しながら重ねる, アスタリスク(6.6.2)のとげを曲線にする,あたりから試してみてください. 数字を 1 つ変えるだけで,まったく違う絵になります.

まとめ

  • 同じ命令の並びを見つけたら,for にまとめる.中身を 1 組だけ書いて,回数を添える
  • for i in range(n): は中身を n 回繰り返す.i0 から n−1 まで変わる.
  • range(a, b)range(a, b, step) で,始まり・終わり・飛ばし幅を決められる.終わりの数は入らない
  • コロンと字下げが,繰り返しの範囲を表す.字下げを間違えると,エラーになるか,黙って別の絵になる.
  • 繰り返しの流れ図は,判断から上へ戻る矢印が付いた形.書く前に絵にしておくと,あとは書き写すだけになる(第 17 章でまた使う).
  • ループ変数を fd(i * 3) のように使うと,1 回ごとに少しずつ違う図形が描ける.
  • 正 n 角形は for i in range(n):rt(360 / n) の 2 行.円は fd(1)rt(1) を 360 回.
  • while は「どうなるまで」の繰り返し.ブラウザでは while True: を使わない(動かし続けたいときは第 10 章の ontimer).
  • for の中に if を書くと,繰り返しながら,あるときだけ違うことをすることができる.
  • 「0 にしておく → 繰り返しの中で足す → 終わってから表示する」が,数を数えるときと合計を求めるときの共通の形.count = count + 1count += 1)を自己代入という.
  • TrueFalse を入れておく変数をフラグといい,「1 回でも見つかったか」を覚えておくのに使う.

次の回では,繰り返しの中に繰り返しを入れます. 正方形を 1 つ描く繰り返しを,さらに 10 回繰り返せば正方形が 10 個. それを縦にも繰り返せば,100 個の格子模様が十数行で描けます.