繰り返し処理をしていると、その途中で繰り返しを終わらせたり、繰り返し処理を一度スキップしたりしたくなることがある。例えば、先ほどは次のようなコードを紹介した。
names = ['一色', 'かわさき', '遠藤']
for name in names:
print(name)
このコードは、リスト(人名録)に保存されたデータを全件画面に表示するものだ。だが、「リストから誰かの名前を探し出して、見つかったら何かの処理をしたい」場合を考えてみよう。これには、前回に紹介したif文を使える。例えば、「かわさき」が見つかったら「発見」と画面に表示して繰り返し処理を終了して、見つからなかったら「見つかりませんでした」と画面に表示することにしよう。上のコードを基に少し改変したのが次のコードだ(実際には、for文を使わなくとも同じ処理は可能だが、ここではサンプルということでご容赦願いたい)。
names = ['一色', 'かわさき', '遠藤']
target = 'かわさき'
for name in names:
if target in name:
print(f'発見: {name}')
else:
print('見つかりませんでした')
for文のブロックでは、if文を使って「変数targetに指定した名前がリストnamesの要素に含まれているかどうか」を調べている。if文の条件には第6回の「in演算子」で紹介した「in」演算子を使って、ループ変数nameに変数targetの値(ここでは文字列'かわさき')が含まれているかを指定している。これはリストの要素が'かわさきしんじ'などであっても、発見できるようにしたいからだ(条件の指定には、この他にも「==」演算子を使う、文字列のfindメソッドを使うなどの方法が考えられる)。
リストnamesの要素から変数targetの値を含んだものが見つかれば、「発見: かわさき」などと表示される。見つからないまま、リストnamesの要素がなくなればelse節が実行されて、「見つかりませんでした」と表示される。実行結果を以下に示す。
人名('かわさき')は見つかったが、最後に「見つかりませんでした」とも表示される。これでは見つかったのか、見つからなかったのかが分からない。なぜ、このような動作になったかというと、人名が発見されたときに、「繰り返し処理を終了」させるコードが書かれていないからだ。ループを途中で終わらせるには「break文」を使用する。
break文は、それを囲んでいる最も内側のループ(for文や次回取り上げるwhile文)を終了させる。このとき、for文やwhile文にelse節があってもそれは実行されない。よって、上のif文のブロック内でbreak文を実行することで、それを囲んでいるfor文の繰り返し処理が終了して、else節の実行もスキップされるようになる。
names = ['一色', 'かわさき', '遠藤']
target = 'かわさき'
for name in names:
if target in name:
print(f'発見: {name}')
break
else:
print('見つかりませんでした')
実行すると、次のようになる。
「for文のelse節」では以下の2つのコードはほぼ同じだと述べた。
for ループ変数 in 反復可能オブジェクト:
ブロック
反復処理終了時に実行するブロック
for ループ変数 in 反復可能オブジェクト:
ブロック
else:
反復処理終了時に実行するブロック
だが、既に述べた通り、break文はelse節の実行をスキップする。そのため、常に両者のコードがほぼ同じ動作になるわけではないことに注意しよう。
break文は「何らかの条件が成立したら、繰り返し処理の途中でそれを終了させる」ためのものだが、「何らかの条件が成立したら、繰り返し処理の途中で処理をスキップして、次の繰り返しに進みたい」こともある。これに使うのがcontinue文だ(これもfor文と次回取り上げるwhile文の両者で使用可能)。
例えば、上のコードを少し変えてみよう。変更点は人名が1つ増えたことと、if文で条件が成立しなかったときに「繰り返し処理を継続します」と表示するようにしたところだ。
names = ['一色', 'かわさき', 'かわさきしんじ', '遠藤']
target = 'かわさき'
for name in names:
if target in name:
print(f'発見: {name}')
break
print('繰り返し処理を継続します')
else:
print('見つかりませんでした')
これを実行すると、次のようになる。
これを実行すると、1つ目の'かわさき'が見つかった時点でbreak文によりfor文の繰り返し処理が終了するので、2つ目の'かわさきしんじ'が見つからない。これで十分な場合もあるが、そうではなく'かわさき'を含んだ要素を全て検索したいときには、「break文でループを終了させる」のではなく「ループを継続させる」必要がある。このようなときにcontinue文を使用する。
ただし、ループ内での処理を全て行った上で、次の繰り返しに移るので問題なければ、continue文は必要ない。ここでは「繰り返し処理を継続します」と画面に表示するのをスキップしたいものとして、continue文を使ってみよう。
continue文は、それを囲んでいる最も内側のループで次の繰り返し処理を開始する。例えば、上のコードでbreak文をcontinue文に置き換えてみよう。
names = ['一色', 'かわさき', 'かわさきしんじ', '遠藤']
target = 'かわさき'
for name in names:
if target in name:
print(f'発見: {name}')
continue
print('繰り返し処理を継続します')
else:
print('見つかりませんでした')
そうすると、リストの要素に変数targetの値(文字列'かわさき')が含まれていたときには、後続の処理(「繰り返し処理を継続します」を表示するprint関数呼び出し)がスキップされて、for文の先頭へ処理が移動して、次の繰り返しが行われる。実行結果を以下に示す。
すると、今度は文字列'かわさき'を含んだ全ての要素が見つかるが、最後に「見つかりませんでした」とも表示されるようになってしまった。なぜかというと、これまでのプログラムはbreak文の実行でelse節の実行がスキップされることに頼ったプログラムの書き方をしていたからだ(それが悪いわけではなく、プログラムに処理したい条件が変わったから、今までの書き方では都合が悪くなったということだ)。
これを修正するには、名前が見つかったかどうかを覚えておく変数が必要になる。見つかったらTrueを、そうでなければFalseを保存しておき、最後にその値を基に「見つかりませんでした」と表示するかどうかを決めればよい。実際のコードは次のようになる。
names = ['一色', 'かわさき', 'かわさきしんじ', '遠藤']
target = 'かわさき'
found = False
for name in names:
if target in name:
found = True
print(f'発見: {name}')
continue
print('繰り返し処理を継続します')
if not found:
print('見つかりませんでした')
変数foundが「見つかったかどうか」を覚えておくためのものだ。初期値をFalseとしてある。if文での人名検索の結果、リストの要素が変数targetの値を含んでいれば、その時点で「見つかった」ことを記憶するために、変数foundの値をTrueにしておく。
最後に「見つかりませんでした」と表示するかどうかを決める部分は、else節に含めても、上のコードのようにelse節から外してfor文と同じインデント位置に書いても構わない(この場合、両者は同等の動作になる)。そこでは、前回に示したブール演算子の一つであるnot演算子を使用して、変数foundの値がFalseの場合(見つからなかった場合)にだけprint関数で「見つかりませんでした」と表示するようになっている。
ここで行っている「繰り返しの中で何らかの状況やフラグの変化を保存しておいて、繰り返し処理が終わった後でそれらを基に処理を分岐させる」というのはよくあることだ。
このコードを実行すると、次のように最後に「見つかりませんでした」と表示されなくなる。
なお、ここで紹介したbreak文とcontinue文も「プログラムの実行の流れ」(フロー)を変更することから「制御構文」に分類されるものだ。
今回はPythonで繰り返し処理を行うために使われる構文であるfor文とbreak文、continue文を紹介した。次回は繰り返し処理で使われるもう一つの構文である「while文」について見ていくことにしよう。
「Python入門」
Copyright© Digital Advantage Corp. All Rights Reserved.