[Pythonクイズ]このリスト内包表記、for文に書き下せますか?Pythonステップアップクイズ

Pythonistaなら積極的に使いたい内包表記。そして同じことを分かりやすく書けるforループ。内包表記とfor文の関係を理解しているかどうかを試してみませんか?

» 2024年12月17日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「Pythonステップアップクイズ」のインデックス

連載目次

内包表記をfor文に書き下せるかな? 内包表記をfor文に書き下せるかな?

【問題】

 以下の2つのリスト内包表記をfor文に書き下したときに(1)から(4)に入るものを選択肢から選びなさい。なお、「 ? 」の部分は大ヒントになるので隠している。

r0 = [s0 + s1 for s0 in 'abc' for s1 in '012']
r1 = [[s0 + s1 for s0 in 'abc'] for s1 in '012']


# 内包表記をfor文に書き下すと……
r0 = []
for (1) in  ? :
    for (2) in  ? :
        r0.append(s0 + s1)

r1 = []
for (3) in  ? :
    tmp = []
    for (4) in  ? :
        tmp.append(s0 + s1)
    r1.append(tmp)

内包表記をfor文に書き下せるかな?

選択肢:

選択肢 (1) (2) (3) (4)
1 s0 s1 s0 s1
2 s0 s1 s1 s0
3 s1 s0 s0 s1
4 s1 s0 s1 s0
答えはどれでしょう?


かわさき

 どうもHPかわさきです。Pythonistaなら使いたいですよね、内包表記。と思っていたのですが、どうもそうでもないこともあるようです。

 先日の編集会議で、普段はRubyをメインに使っていて、たまにはPythonも使うよって人から「え? 内包表記? そんなによく使うの?」みたいなコメントをもらったんですよね。彼は筆者よりもプログラミングのスキルは高いし、使っている言語もたくさん、アイデアもあふれているしと、そりゃーもう素晴らしいプログラマー。そんな彼からそんな言葉を聞くとはちょっと意外だったのです。

 でもよく考えてみると、他の言語でたくさんの経験があるプログラマーがちょこっとしたことをやりたいときに、(便利そうなフレームワークがたくさんあるという理由で)Pythonを手にしたらどうなんでしょう。Pythonに特有の内包表記なんて使わないで、これまでに自分が身に付けてきた知識と経験を基にしたコードを書くのは当たり前のような気もします。

 このことについて特に結論はないんですが、取りあえず今回は内包表記の問題です。Pythonistaなら使いたいですよね?(そうでもない?)


【答え】

 答えは選択肢2の「(1)s0 (2)s1 (3)s1 (4)s0」です。分かりましたか? 正解のコード例を以下に示します。

r0 = [s0 + s1 for s0 in 'abc' for s1 in '012']
r1 = [[s0 + s1 for s0 in 'abc'] for s1 in '012']

# 内包表記をfor文に書き下すと……
r0 = []
for s0 in 'abc':
    for s1 in '012':
        r0.append(s0 + s1)

r1 = []
for s1 in '012':
    tmp = []
    for s0 in 'abc':
        tmp.append(s0 + s1)
    r1.append(tmp)

正解のコード例

 1つ目の内包表記は、その中でfor節がネストするもので、2つ目の内包表記はその式部分が内包表記になっている(内包表記がネストしている)ものです。この違いにより2つの変数s0とs1を使ったforループの順番が逆になっています。

変数s0とs1を使ったforループの順番が逆になっている 変数s0とs1を使ったforループの順番が逆になっている


かわさき

 ちなみにこれらのコードの実行結果はもちろん違うものです。前者は1次元のリストで、後者は2次元のリストというのはもちろん大きな違いですが、それ以上に要素の並び順が異なっていることに注意しましょう。以下に実行結果を示します。

実行結果 実行結果

 なんでそうなるかについては解説の最後で話します。


【解説】

 まずは1つ目の内包表記について見てみましょう。以下はリスト内包表記と対応するfor文です。

r0 = [s0 + s1 for s0 in 'abc' for s1 in '012']

r0 = []
for s0 in 'abc':
    for s1  in '012':
        r0.append(s0 + s1)

1つ目の内包表記とそれをfor文に書き下したコード

 書き下したコードを見ると、ネストしたfor節がそのままの順番でfor文に置き換えられていることが分かります。このことについては、Pythonのドキュメントに次のような記述があります。

 内包表記はまず単一の式、続いて少なくとも1個のfor節、さらに続いて0個以上のfor節あるいはif節からなります。この場合、各々のfor節やif節を、左から右へ深くなっていくネストしたブロックとみなし、ネストの最内のブロックに到達するごとに内包表記の先頭にある式を評価した結果が、最終的にできあがるコンテナの各要素になります。

 重要なのは「各々のfor節やif節を、左から右へ深くなっていくネストしたブロックとみなし」というところです。ここがストンと腑(ふ)に落ちれば、上のようなforループになることがすぐに分かるでしょう。


かわさき

 でも、「ドキュメントを読むだけだと意味がよく分からない」ってなりますよねぇ。多分、筆者はここを何度も読んでいるはずなのに、スカッと読み飛ばしていた気がします。ところがどっこい、コードと一緒にドキュメントを読んでみれば「ああ、なるほど!」となるので、ドキュメントの意味を具体的に示すコードはとても重要だなと思いました(小並感)。

 そういえば、高校生の頃、数学の宿題が分からずに、友だちからノートを借りてまるっと写させてもらったことがあります。そのときには「なーんで、この式がこういうふうに変形するんだよ。頭のいいヤツが考えることは全く分からん」となったことがあります。でも、その部分の理解が進んで、同種の問題を自力で解いてみると友だちのノートのようにしか書けないことが分かったのです。それと通じるところがあるかもしれませんね(この文章、後から読み返してみましたが、そうでもないかな)。

 ドキュメントの理解とコードの実践は、実力を上げる両輪みたいなものなのかもしれませんね。


 要するに、内包表記でfor節が連続したときにはそれらはそのままの順番でfor文として書き下せると覚えておけばよいでしょう。

 そして、2つ目の内包表記とそれを書き下したfor文は次のようなものでした。

r1 = [[s0 + s1 for s0 in 'abc'] for s1 in '012']

r1 = []
for s1  in '012':
    tmp = []
    for s0 in 'abc':
        tmp.append(s0 + s1)
    r1.append(tmp)

2つ目の内包表記とそれをfor文に書き下したコード

 先ほどは「2つ目の内包表記はその式部分が内包表記になっている(内包表記がネストしている)ものです」と書きました。上で引用したPythonのドキュメントに当てはめてみると「内包表記はまず単一の式、続いて少なくとも1個のfor節、さらに続いて0個以上のfor節あるいはif節からなります」という部分の「単一の式」が内包表記になっていて、その後に続くfor節は1つだけと考えられます。

 そのため、まずは外側の内包表記のfor節である「for s1 in '012'」が外側のfor文になり、単一の式である内包表記のfor節である「for s0 in 'abc'」が内側のfor文になったということですね。

 ここまでくれば、要素の並び順が2つの内包表記で異なるのもすぐに分かるでしょう。1つ目の内包表記では、最初に文字列'abc'の各文字を見ていきます(外側のループ)。例えば'a'については、次に文字列'012'の各文字を見ていきます(内側のループ)。この順番で処理を進めることで、以下の表のように要素が作られます。

外側のループ 内側のループ 作られる要素
'a' '0'→'1'→'2' 'a0', 'a1', 'a2'
'b' '0'→'1'→'2' 'b0', 'b1', 'b2'
'c' '0'→'1'→'2' 'c0', 'c1', 'c2'
1つ目の内包表記

 対して、2つ目の内包表記では、最初に文字列'012'の各文字を見ていきます(外側のループ)。例えば'0'については、次に文字列'abc'の各文字を見ていきます(内側のループ)。この順番で処理を進めることで、以下の表のように要素が作られます。

外側のループ 内側のループ 作られる要素
'0' 'a'→'b'→'c' ['a0', 'b0', 'c0']
'1' 'a'→'b'→'c' ['a1', 'b1', 'c1']
'2' 'a'→'b'→'c' ['a2', 'b2', 'c2']
2つ目の内包表記

 Pythonistaとしては積極的に使っていきたい内包表記ですが、慣れも必要です。これからもクイズの問題として取り上げていくので、実力を上げるために一緒に解いていきましょうね。


かわさき

 毎回恒例の「Python入門」へのリンクを紹介するお時間です。リスト内包表記については「リストの基本」の「リスト内包表記」で解説しているので、興味のある方はそちらにもぜひ目を通していただけたら幸いです。


「Pythonステップアップクイズ」のインデックス

Pythonステップアップクイズ

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。