繰り返す
同じ命令を何度も書かない.「何回」だけを伝えます.
第 2 章で正十角形を描いたとき,fd(40) と rt(36) を
10 回ずつ,合わせて 20 行書きました.書いているうちに
「これは人間のやる仕事ではない」と思ったはずです.その感覚が正しいのです.
同じことを何度も繰り返すのは,コンピュータが一番得意な仕事です. 人間は「何を何回するか」だけを書けばよい.今回はそのための書き方, 繰り返し(ループ)を習います.今日を境に,プログラムの長さと 絵の複雑さは関係がなくなります.
forとrangeを使って,同じ命令の繰り返しを短く書ける- コロンと字下げで,どこからどこまでが繰り返しの中かを指定できる
range(n)・range(a, b)・range(a, b, step)を使い分けられる- 繰り返しの流れ図(フローチャート)が読め,それをプログラムに写せる
- ループ変数
iを使って,1 回ごとに少しずつ違う図形が描ける - 正 n 角形や円を,回数と角度の計算から描ける
- 字下げの間違いで起きるエラーを読んで,自分で直せる
- 繰り返しの中に
ifを書いて,あるときだけ違うことをさせられる count = count + 1・total = total + i(自己代入)で,数を数える・合計を求めることができる
6.1 同じことを何度も書いている
6.1.1 どこが同じかを探す
繰り返しの書き方を習う前に,まず「何を繰り返すのか」を見つける練習をします. 第 2 章で書いた家のプログラムを,もう一度見てください.
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 回.
100 や 120 が縦に並んでいたら,そこはほぼ確実に繰り返しです.
6.1.2 繰り返しで書き直す
見つけた繰り返しを,今日習う for で書き直したものが次です.
描かれる絵はまったく同じで,行数だけが減っています.
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()
fd と rt が並んでいた部分が,
「中身を 1 組だけ書いて,回数を添える」形になりました.
これが今回いちばん大事な発想です.
6.1.3 正十角形を 3 行にする
第 2 章の虫食いで,fd(40) と rt(36) を 10 回ずつ
書かされたのを覚えているでしょうか.あの 20 行は,次の 3 行と同じ意味です.
from turtle import *
pensize(2)
pencolor("indigo")
for i in range(10):
fd(40)
rt(36)
done()
10 を 36 に,rt(36) を
rt(10) に変えてみてください.正三十六角形になります.
手書きなら 72 行の作業が,2 か所の数字を直すだけで済みます.
6.2 for の書き方
6.2.1 形を覚える
繰り返しの書き方は次のとおりです.1 文字も省略できません.
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 行とまったく同じ意味です.
fd(100) lt(90) fd(100) lt(90) fd(100) lt(90) fd(100) lt(90)
SyntaxError: expected ':',
字下げを忘れると IndentationError: expected an indented block が出ます.
どちらも「for の行の最後にコロン,次の行から字下げ」を
覚えていれば起きません.
6.2.2 どこまでが繰り返しの中か
Python では,字下げしてある行だけが繰り返されます.
字下げをやめた行から先は,繰り返しが全部終わってから 1 回だけ実行されます.
次の 2 つを見比べてください.違いは fd(120) の行の
字下げだけです.
左は正三角形を描いてから赤い線を 1 本引きます. 右は三角形の 1 辺を描くたびに赤い線を引くので,形が変わります. 字下げは見た目を整えるためのものではなく,意味そのものです.
from turtle import *
pensize(2)
for i in range(3):
fd(80)
lt(120)
pencolor("crimson")
fd(120) # ← 字下げしていない.繰り返しが終わってから 1 回だけ
done()
Tab キーを押すと 4 つ分の空白が入ります.
途中で 2 つにしたり 8 つにしたりすると,エラーになったり,
思っていないところまで繰り返されたりします.
1 辺 60 の正六角形を for で描きます.
2 つの ____ を埋めてください.
角の数は 6,曲がる角度は 360 ÷ 6 でしたね.
from turtle import *
pensize(2)
pencolor("seagreen")
for i in range(____):
fd(60)
rt(____)
done()
6.3 流れ図で見る繰り返し
第 5 章で,if の流れを絵にした
流れ図(フローチャート)を見ました(第 5 章 5.1.3 節).
繰り返しも,同じ記号で絵にできます.
ちがうのは,もと来たところへぐるっと戻る矢印が付くことだけです.
6.3.1 流れ図の記号
使う記号は 4 つだけです.第 5 章と同じものです.
| 記号 | 名前 | 何を表すか |
|---|---|---|
| 角丸の四角 | 端子 | はじめ・おわり |
| 長方形 | 処理 | 実際にやること(fd(100),値を入れる,など) |
| ひし形 | 判断 | 条件を調べるところ.はいといいえで道が分かれる |
| 矢印 | 流れ | 次にどこへ行くか.上に戻る矢印があれば繰り返し |
6.3.2 for の流れ図
for i in range(4): を流れ図にすると,次のようになります.
for i in range(4): の流れ図.中身を実行したら,判断のところへ戻る.上から順に読んでみてください.やっていることは 4 つです.
- ① i を 0 にする(はじめの値を決める)
- ② i はまだ 4 より小さいかと調べる(まだ残っているか)
- ③ 小さければ中身を実行する
- ④ i に 1 を足して,②へ戻る
②へ戻るたびに i は 1 ずつ大きくなり,
0 → 1 → 2 → 3 と進みます.
i が 4 になったところで
「4 より小さいか」がいいえになり,繰り返しが終わります.
中身が実行されたのは,ちょうど 4 回です.
for の 3 行と見くらべてください.
プログラムに書いてあるのは,「4 回」と「中身」だけです.
①②④は書いていません.それでも動くのは,
for と range が代わりにやってくれているからです.
6.3.3 while の流れ図
繰り返しにはもう一つ while という書き方があります
(くわしくは 6.8 節で習います).
while は「条件が成り立つ間くり返す」という書き方で,
流れ図にすると,for よりも素直な形になります.
while 条件式:
繰り返す中身
while 条件式: の流れ図.条件を調べてから中身へ進む.ここで大事なのは,判断がいちばん先に来ていることです. 中身へ進む前に,かならず条件を調べます. ですから,はじめから条件が成り立たなければ,中身は 1 回も実行されません.
i = 10 の状態で while i < 4: と書くと,
いちばん最初の判断でいいえになり,
中身を素通りして,すぐ次の行へ進みます.
「少なくとも 1 回は実行される」と思いこまないでください.
流れ図を見れば,それが一目で分かります.
6.3.4 for と while を見くらべる
同じ「4 回くり返す」を,for と while で書いたときの
流れ図を並べてみます.形はまったく同じです.
for と while の対応.点線の 3 つは for が引き受けてくれる.while で書くと,はじめの値・続ける条件・1 増やす,の
3 つを自分で書くことになります.
そのぶん,書き忘れる場所も 3 つあります.
とくに「1 増やす」を書き忘れると,条件が永遠に成り立って終わりません.
for を使ってください.
while は「何回で終わるか,書く前には分からない」ときのための書き方です.
この教材では while True:(ずっと繰り返す)は使いません
(理由は 6.8.2 節にあります).
図 6.8 の右側,while のほうの流れ図を,
そのままプログラムに写します.
____ は 3 か所です.
- はじめの値 …
iをいくつから始めますか. - 続ける条件 …
iが 4 より小さい間です. - 増やす数 … 1 回ごとにいくつ増やしますか.
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 で確かめましょう.
for i in range(5):
print(i)
print("おしまい")
コンソールに 0 1 2 3 4 が縦に並び,最後に
おしまい と出ます.print(i) は字下げの中にあるので
5 回実行され,print("おしまい") は外にあるので 1 回だけです.
print(i) を 1 行入れて,実際の値を見るのが確実です.
6.4.2 range の 3 つの書き方
| 書き方 | 作られる数 | 個数 |
|---|---|---|
range(5) | 0, 1, 2, 3, 4 | 5 個 |
range(1, 6) | 1, 2, 3, 4, 5 | 5 個 |
range(0, 10, 2) | 0, 2, 4, 6, 8 | 5 個 |
range(20, 160, 20) | 20, 40, 60, 80, 100, 120, 140 | 7 個 |
range(10, 0, -1) | 10, 9, 8, …, 1 | 10 個 |
3 つめの数は「いくつ飛ばしか」を表し,step といいます. マイナスにすると減っていきます.どの書き方でも 終わりの数そのものは入らないことに注意してください.
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()
上のプログラムと同じ形です.20 から 140 まで 20 ずつ長くするには,
range に何と何を書けばよいでしょうか.
____ を 2 つ埋めてください.
終わりの数は入らないことを思い出してください.
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)は負の数でもかまいません. そのときは,大きいほうから小さいほうへ減りながら繰り返します. ロケットの発射カウントダウンのように,逆向きに数えたいときに使います.
# 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)
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 回ごとに値が変わるので,
それを fd や rt の中に書くと,
毎回少しずつ違う動きをさせられます.
6.5.1 だんだん長くなる渦巻き
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()
rt(90) にすると正方形に戻る.fd(i * 3) の 3 や,rt(91) の
91 をいろいろ変えてみてください.
rt(90) にするとぴったり重なって正方形になり,
rt(120) にすると三角の渦になります.
渦巻きを描きます.i 回目の線の長さを
i の 3 倍にしてください.
____ に入るのは数ではなく,
i を使った式です.
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 周します.
from turtle import *
pensize(2)
pencolor("royalblue")
for i in range(360):
fd(1)
rt(1)
done()
6.5.3 円の大きさは何で決まるか
fd の数(1 回に進む長さ)と rt の数(1 回に曲がる角度)を
変えると,円の大きさが変わります.ただし
「1 周ぶん回る」という条件は守らなければなりません.
角度を rt(5) にしたら,繰り返す回数は 360 ÷ 5 = 72 回です.
fd(2)・rt(5) を 72 回fd(6) にすると 3 倍の大きさrt(15)・24 回.角ばって見える- 1 周するには (曲がる角度)×(回数)= 360 になっていること.
- 円の周の長さは (進む長さ)×(回数).これが大きいほど大きな円になる.
- 角度を大きく,回数を少なくすると,角ばって多角形に見える.
fd(6) と rt(5) の組で円を描きます.
ちょうど 1 周するには何回繰り返せばよいでしょうか.
____ を埋めてください.
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 です.
from turtle import *
n = 12 # ← ここだけ変える
length = 40
pensize(2)
pencolor("teal")
for i in range(n):
fd(length)
rt(360 / n)
done()
n = 12 のとき.正十二角形になる.n を 3 にすれば正三角形,5 にすれば正五角形,
50 にすればほとんど円になります.プログラムは 1 文字も変えません.
これが「変数」と「繰り返し」を組み合わせたときの強さです.
360 / n は,n が 7 のときに
51.42857142857143 のような小数になります.
かめは小数の角度でもきちんと曲がるので,そのままで問題ありません.
整数にしたいときは 360 // n と書きますが,
誤差が積もって図形が閉じなくなるので,ここでは / を使ってください.
n の値を使って正 n 角形を描きます.
____ を 2 つとも n を使った形で埋めてください.
数字をそのまま書いてしまうと,n を変えたときに形が崩れます.
from turtle import *
n = 9
pensize(2)
pencolor("darkorange")
for i in range(____):
fd(50)
rt(360 / ____)
done()
6.6.2 星・アスタリスク
第 2 章で 10 行かけて書いた星も,繰り返しなら 3 行です. とげのような図形(アスタリスク)も, 「進んで戻って少し回る」を繰り返すだけで描けます.
rt(144) を 5 回from turtle import *
pensize(2)
pencolor("orangered")
for i in range(8):
fd(60)
bk(60)
rt(45)
done()
360 ÷ 8 = 45 度ずつ回っている.range(8) を range(12) に,
rt(45) を rt(30) に変えます(360 ÷ 12 = 30).
回数と角度はいつも一緒に変えると覚えてください.
6.7 字下げを間違えるとどうなるか
繰り返しでいちばん多い失敗は,命令の書き間違いではなく 字下げです.わざと間違えて,何が起きるかを先に見ておきましょう.
6.7.1 字下げが無い(IndentationError)
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) の字下げが足りません.
from turtle import *
pensize(2)
pencolor("crimson")
pu()
goto(-200, 0)
pd()
for i in range(4):
fd(100)
lt(90) # ← 字下げしていない!
done()
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
になります.「その字下げの深さは,どのかたまりにも当てはまらない」という意味です.
同じかたまりの中は,すべて同じ幅で字下げしてください.
| 症状 | 原因と直し方 |
|---|---|
SyntaxError: expected ':' | for の行の最後にコロンが無い |
IndentationError: expected an indented block | for の次の行を字下げしていない |
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 条件式:
繰り返す中身
条件式が成り立っている間,中身が繰り返されます. 1 回終わるたびに条件式をもう一度調べ,成り立たなくなったところで終わります.
from turtle import *
pensize(2)
pencolor("seagreen")
length = 10
while length < 150:
fd(length)
rt(90)
length = length + 10 # ← これを忘れると終わらない
done()
length = length + 10 は,
「今の length に 10 を足したものを,あらためて length に入れる」
という意味です.この行を書き忘れると条件が永遠に成り立ち,
繰り返しが終わりません.while を使うときの最大の注意点です.
6.8.2 ブラウザでは 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 回目は不成立」というように,回ごとに違う動きをします.
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()
length は 1 回ごとに変わるので,
if length > 100: の答えも 1 回ごとに変わります.
短い線が青,長い線が赤になり,どこで色が変わったかが目で見て分かります.
100 を 50 や 150 に変えて,境目が動くのを確かめてください.
forの中身は4 つ字下げ.- その中の
ifの中身は,さらに 4 つ足して8 つ字下げ. fdとbkはifの外(4 つ字下げ)なので,毎回かならず実行されます.
fd(length) の行をうっかり 8 つ字下げすると,
長い線しか引かれなくなります.
エラーは出ません.出るのは「思っていたのと違う絵」だけです.
思った絵にならないときは,行の左端を縦に見てそろっているか確かめてください.
なお,if は繰り返しの外に書いたほうがよいこともあります.
次は「kind が 1 なら * を,そうでなければ $ を 5 個並べる」
プログラムです.
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 という書き方,
つまり自己代入の出番です.
- 繰り返しに入る前に,
count = 0と置く. - 数えたい場面に来るたびに
count = count + 1で 1 増やす. - 繰り返しが終わってから,
countを表示する.
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 に入れる」と読みます.
| 何回目 | length | length > 100 | この行のあとの count |
|---|---|---|---|
| 0 回目 | 0 | 不成立 | 0 |
| … | … | … | 0 |
| 8 回目 | 96 | 不成立 | 0 |
| 9 回目 | 108 | 成立 | 1 |
| 10 回目 | 120 | 成立 | 2 |
| … | … | … | … |
| 17 回目 | 204 | 成立 | 9 |
+= という書き方
count = count + 1 は count += 1 とも書けます.
+= を累算代入演算子といい,
-=・*=・/= も同じように使えます.
プロのプログラムではほとんど += が使われますが,
慣れるまでは count = count + 1 と書いて,
右を計算してから左に入れるという流れを意識してください.
count = 0 を繰り返しの中に書いてしまうと,
毎回 0 に戻されるので,最後はいつでも 0 か 1 にしかなりません.
数える箱は,繰り返しに入る前に 1 回だけ用意します.
6.9.3 合計を求める
数える代わりに足していけば,合計が求められます. 「1 から 10 までの合計」を,1 行も足し算を書かずに計算してみましょう.
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 の書き方を変えれば,足す相手も自由に変えられます.
+= を使って短く書いてみます.
# 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)
6.9.4 見つかったかどうかを覚えておく
「繰り返しの途中で 1 回でも条件が成立したか」を,
あとから知りたいことがあります.
このときは True か False を入れておく変数を使います.
こういう変数をフラグ(旗)といいます.
- 繰り返しに入る前に
found = False(まだ見つかっていない)と置く. - 見つけたら
found = Trueに書き換える. - 繰り返しが終わってから
foundをifで調べる.
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 の中身がもともと True か False なので,
わざわざ == True と比べなくてもよい,というわけです.
どちらで書いてもかまいません.
found = False を書き忘れると,繰り返しの中で 1 度も成立しなかったとき,
found という変数が存在しないまま
最後の if にたどりつき,NameError になります.
第 5 章で習った,「先に初期値を入れておく」という話とまったく同じです.
3, 4, 5, 6, 7 をぜんぶ足した合計を求めます.
____ を 4 つ埋めてください.
答えは 25 になるはずです.
終わりの数は入らないことを思い出してください.
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 は負でもよい |
:(コロン) | for や while の行の最後に必ず付ける |
| 字下げ(半角 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 = False → True | フラグ.「1 回でも成立したか」を覚えておく |
print(i) | ループ変数の値を確かめる.デバッグの基本 |
演習
「▶ この演習を開く」で右側に読み込み,それを発展させて作品にしてください. できあがったら「⤓ 保存」でファイルに保存して,手元に残しておきましょう. どの演習も,繰り返しを必ず使うことが条件です.
繰り返しで円を描くプログラムを与えます.これをもとに,
大きさや色の違う円を 3 つ以上組み合わせた絵を作ってください.
雪だるま,信号機,オリンピックの輪,水面の波紋 — 何でもかまいません.
位置をずらすには pu() と goto() を使います.
1 回に進む長さと曲がる角度を変えると,円の大きさがどう変わるかを実験します.
出発点のプログラムは,step と angle を変えるだけで
いつもちょうど 1 周するようになっています.
stepを 1・2・4・8 と変えて実行し,大きさの変化を見る.angleを 1・5・15・30 と変えて実行し,形の変化を見る.- 思ったとおりの大きさの円を描くにはどうすればよいかを,プログラムの先頭にコメントで 2〜3 行にまとめる.
// は「割り算の商(整数)」を求める記号です.
360 // 7 は 51 になります.
angle は 360 を割り切れる数(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, …)
にすると,きれいに 1 周します.
繰り返しで正方形を描くプログラムを与えます.これをもとに,
正方形を並べる・重ねる・少しずつ回すなどして模様を作ってください.
for の中の i を fd の中で使うと,
大きさの違う正方形が簡単に描けます.
繰り返しで正五角形を描くプログラムを与えます.
大きさの違う正五角形を重ねる,
角の数を変えて別の正多角形にするなど,自由に発展させてください.
6.6 節のように n を変数にすると,一度にいろいろ試せます.
繰り返しで星を描くプログラムを与えます.
大きさや色の違う星を 3 つ以上並べて,夜空や旗の模様を作ってください.
rt(144) を rt(160) などに変えると,
とがり方の違う星になります.
「進んで,戻って,少し回る」を繰り返してとげを描くプログラムを与えます. とげの本数・長さ・色を変えて,花火や雪の結晶のような図を作ってください. とげ 1 本を長くしたり短くしたりすると,形が大きく変わります.
繰り返しを使って,好きな絵を描いてください.
同じ命令を手で何度も書いてはいけません.
繰り返せるところは必ず for にしてください.
forを2 か所以上使うこと- ループ変数
iをfdかrtの中で1 回は使うこと(毎回少しずつ変える) - 色(
pencolor)と太さ(pensize)を使うこと - 先頭にコメントで,題名・氏名・日付を書くこと
- 仕上げに
ht()を入れると作品らしくなる
まとめ
- 同じ命令の並びを見つけたら,
forにまとめる.中身を 1 組だけ書いて,回数を添える. for i in range(n):は中身を n 回繰り返す.iは 0 から 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 + 1(count += 1)を自己代入という. True・Falseを入れておく変数をフラグといい,「1 回でも見つかったか」を覚えておくのに使う.
次の回では,繰り返しの中に繰り返しを入れます. 正方形を 1 つ描く繰り返しを,さらに 10 回繰り返せば正方形が 10 個. それを縦にも繰り返せば,100 個の格子模様が十数行で描けます.