whileで繰り返す

このレッスンで作るもの — 「終了」と入力されるまで記録を受け付け続ける collect_until_end を、while で作ります。

while で繰り返す

for は「並んでいるものを最後まで回す」ループでした。回る回数は始まる前から決まっています。

ところが、おこづかい帳に何件記録するかは、使う人にしか分かりません。3 件で終わる日もあれば 20 件の日もあります。このように 何回回るか分からない繰り返し を書くのが while です。

for は「全部に対して」、while は「条件が成り立つあいだ」。どちらを使うか迷ったら、回数が先に決まっているかどうかで選びます。

while の形

while のうしろには 条件 を書きます。条件が True のあいだ、下にインデントした処理を繰り返します。

count = 0 while count < 3: print(count) count = count + 1

このコードは 012 を表示して止まります。4 周目に入ろうとしたとき count3 になっており、3 < 3False なので繰り返しが終わります。

if と形がよく似ていますが、if は条件を 1 回だけ 調べるのに対し、while1 周まわるたびに調べ直す ところが違います。

count = count + 1 の行がとても大事です。この行を書き忘れると count0 のままで、条件がいつまでも True になり、プログラムが止まらなくなります。これを 無限ループ と呼びます。

while を書いたら、その場で「この条件はどうやって False になるのか」を口に出して確認します。答えられないなら無限ループです。

本来は input を while で回す

このアプリで本当にやりたいのは、下記のような形です。キーボードから入力を受け取り、「終了」と打たれるまで受け付け続けます。

items = [] while True: text = input("品名を入力してください ") if text == "終了": break items.append(text) print(items)

while True は「条件がいつも成り立つ」ので、そのままでは永遠に回ります。止める役目を break が担っています。break はループを途中で抜ける命令で、次のレッスンで詳しく扱います。

items.append(text) は、リストのうしろに 1 件足す命令です。リストの操作は第 7 章で詳しく扱いますが、ここでは「結果をためる入れ物に 1 件足す」道具として使います。

演習では入力を引数で受け取る

このコースの採点は、関数が return した値を見て正解かどうかを判定します。キーボードは繋がっていないので、input() は使えません。

そこで演習では、入力されるはずだった文字列の並びをリストで受け取る 形にします。input() を 1 回呼ぶ代わりに、リストから 1 件取り出す、と読み替えるわけです。

def collect_until_end(inputs): items = [] i = 0 while i < len(inputs): text = inputs[i] if text == "終了": break items.append(text) i = i + 1 return items

len(inputs) はリストの件数、inputs[i]i 番目の 1 件です。どちらも第 7 章で詳しく扱う道具で、ここでは「次に読む位置を i で進めていく」ために借りています。i が件数に届いたら、もう読むものがないのでループが終わります。

diagram (will load when visible)

collect_until_end(["りんご", "みかん", "終了", "パン"]) を呼ぶと、りんごみかん を取り込んだところで 終了 に当たって止まります。うしろの パン は読まれないので、返るのは ["りんご", "みかん"] です。

「終了の合図が来たら止める」という考え方は、この先どんなアプリにも出てきます。合図の文字列だけを変えれば、そのまま使い回せます。

よくある間違い

  1. カウンタを進め忘れるi = i + 1 を書き忘れると、同じ 1 件を永久に読み続けます。手元で試すときは、止まらなくなったら Ctrl + C で強制終了できます。
  2. i = i + 1break の前に置いてしまう — 位置そのものは動きますが、終了items に入れてしまう順番になっていないか、必ず読み返します。取り込むのは 終了 ではない行だけです。
  3. while の条件を i <= len(inputs) にしてしまう — 最後の 1 件を読んだあと、存在しない位置を読もうとして IndexError になります。件数が 3 なら読める位置は 0 と 1 と 2 までです。

終了 が 1 件も含まれていない場合は、最後まで読み切って自然にループが終わります。特別な場合分けは要りません。

やってみよう

関数 collect_until_end を実装してください。引数 inputs は文字列のリストで、入力されるはずだった品名が順番に並んでいます。

先頭から順に見ていき、"終了" に当たったらそこで止め、それより前の品名だけを並べたリストを return します。"終了" が含まれていない場合は、全部を並べたリストを返します。空のリストを渡されたときは空のリスト [] を返します。

for でも書けますが、今回は while で書いてみてください。input() を繰り返す形と、頭の中で重ねられるはずです。

要件

  1. 関数名は collect_until_end で、引数はリスト inputs の1つだけにする
  2. while を使って先頭から順に見ていく
  3. "終了" に当たったらそこで止め、それより前の品名だけを返す
  4. "終了" が無い場合と空のリストの場合も正しく動くようにする

入出力例

collect_until_end(["りんご","みかん","終了","パン"])["りんご","みかん"] collect_until_end(["りんご","みかん"])["りんご","みかん"] collect_until_end(["終了","りんご"])[] collect_until_end([])[] collect_until_end(["パン"])["パン"]

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.py
main.py
学習モード

メモ

whileで繰り返す

⌘S で保存