[Pythonクイズ]このfor文の実行結果、正しく予想できる?:Pythonステップアップクイズ
Pythonのfor文には他の言語にはないヘンな節があります。使ったことがある人もない人も、その動作をちゃんと理解していますか?
【問題】
以下に示すコードではpersonsというリストに'HPK'が含まれているかどうかを判断しようとしている。これを実行するとどんな結果が出るだろう。
persons = ['isshiki', 'endo', 'HPK']
for p in persons:
if p == 'HPK':
print('found: HP Kawasaki')
else:
print('not found: HP Kawasaki')
以下の選択肢から答えよ。
- 「found: HP Kawasaki」と表示される
- 「not found: HP Kawasaki」と表示される
- どちらでもない
もっとよい書き方があるんじゃない?
問題文のコードを書いていて筆者はこう思いました。「いや、普通はこんなコードは書かないよね」と。というわけで、ChatGPT 5/Claude Opus 4.1/Gemini 2.5 Proの3つのLLMに「上のコードを書き直してみて」と聞いてみたのです。
果たして、LLMたちは筆者が考えるコードをちゃんと提案してくれたのでしょうか? その結果は最後にお知らせしましょう。
どうもHPかわさきです。
2週間のお休みを頂いてしまいました。「ネタ切れ?」と思う方もいらっしゃるでしょう。でも、そうじゃないんですよ。手元にネタのストックはあるのですが、それらを見ていて「うーん。コレじゃないなぁ」って考えることもあるんですよね。例えば、PEP 8関連のネタばかりをやってもしょうがないじゃないですか。そういうのはある程度期間を置いて、またやるというのがいいかなと。リストの要素うんぬんばっかりやるのもアレだしとか。
というわけで、今回はfor文です。きっと多くの人が使うことはないfor文のアレがテーマなので、あんまり実用には役立たないのかなぁと思いながらも、覚えておくのは大事だよってことで問題を作ってみました。ご照覧ください(あ、もうしてるか)。
【答え】
正解は選択肢3の「どちらでもない」でした。
for文の中のif文で条件が成立したときにループを終了するようにbreak文を入れていないために、if文で条件が成立したところで「found: HP Kawasaki」と表示され、for文の終了時(全ての要素の反復を終えたとき)に「not found: HP Kawasaki」と表示されてしまうのです。
【解説】
Pythonのfor文には他の言語にはあまり見られないelse節があります(while文にもあります)。else節についてPythonのドキュメント「ループのelse節」では「for文の場合、else節はループ処理の最後のイテレーションが実行された後、つまりbreakが発生しなかった場合に実行されます」とあります。
例えば、for文の中でif文が実行され、そのいずれかの節(if節、elif節、else節)でbreak文が実行されると、for文(正確にはbreak文を囲む最も内側のループ)が終了しますが、このときにはelse節に書いたコードは実行されません。
一方、break文を実行することなく、for文で指定した反復可能オブジェクトの要素を使い果たしたときにはelse節に書いたコードが実行されるということです。
以上を踏まえて、問題のコードを見てみましょう。
persons = ['isshiki', 'endo', 'HPK']
for p in persons:
if p == 'HPK':
print('found: HP Kawasaki')
else:
print('not found: HP Kawasaki')
パッと見て分かる通り、break文がありません。上の説明と照らし合わせてみると、このコードではpersonsの要素を使い果たしたところでelse節のコードが実行され「not found: HP Kawasaki」と表示されるということです。
それはともかくとして、コードの動作を確認してみましょう。
for文の中にはif文があります。そのif文ではリストから取り出した要素と'HPK'を比較して見つかったら「found: HP Kawasaki」と表示するようになっています。でも、上で述べたように最後には「not found: HP Kawasaki」とも表示されてしまいます。それがなぜかといえば、if文の中で条件(リストの要素が'HPK'と等しい)が成立したときにループを終了するようにしていないからです。
具体的に見ていくと、ループの1周目(pは'isshiki')、2周目(pは'endo')ではif文の条件は成立しません。そのため何もせずにfor文の先頭に実行が戻ります。そして、3周目ではpが'HPK'となり条件が成立するため、「found: HP Kawasaki」と表示されます。ですが、break文がないので、ループはここで終わらず、for文の先頭に実行が戻ります。そして、これ以上リストの要素がないので、ここでfor文が終わります。break文が実行されていないので、この時点でelse節が実行され、「not found: HP Kawasaki」も表示されてしまうのです。
'HPK'が見つかった時点でbreak文でループを終了するようにすれば、else節は実行されなくなるので、上のコードをそのままの形で直すとしたら次のようになるでしょう。
persons = ['isshiki', 'endo', 'HPK']
for p in persons:
if p == 'HPK':
print('found: HP Kawasaki')
break
else:
print('not found: HP Kawasaki')
こうすれば、'HPK'が見つかった時点で「found: HP Kawasaki」と表示して、ループをbreakするのでelse節が実行されなくなり、「not found: HP Kawasaki」と表示されることもなくなります。
このことから言えるのは「for文にelse節を持たせるのであれば、(恐らくは)ループを途中で終了するようなbreak文を書くことになるだろう」ということです。「else節を書かなきゃならない」というときにはコード全体の構造を見直して、なるべくelse節を書かないようにすることを考えてみるのもよいかもしれません。
さて、LLMに「書き直してみてよ」と聞いてみた結果の発表のお時間がやってきました。まず、筆者がどんなコードを書いてほしかったかというと、次のようなコードです。
persons = ['isshiki', 'endo', 'HPK']
if 'HPK' in persons:
print('found: HP Kawasaki')
else:
print('not found: HP Kawasaki')
for文でリストの要素を反復して、その要素と何かの値を比較するよりも、Pythonのin演算子を使ってリストに特定の要素が含まれているかどうかをチェックする方が簡単です。LLMがそこまで考えてコードを書き直してくれるのか? それとも単にbreak文がないことに着目してbreak文を含んだコードだけを返してくるのか? そんなところを見たいと思ったのです。
では、in演算子を使ったコードまで提案してくれたLLMとそうではなかったLLMはどうなったでしょう? 結果は次の通りです!
なんと! 3つのLLM全てがin演算子を使った方がシンプルですよってコードを提案してくれました。まいりました(orz)。
というわけで、for文については「Python入門」の「for文による繰り返し処理」でも触れているので、興味のある方はそちらもご覧になってくださいね。
Copyright© Digital Advantage Corp. All Rights Reserved.