検索
連載

[Pythonクイズ]2つのリストから辞書を作成する方法 あの方法とその方法、どっちなんだい?Pythonステップアップクイズ

辞書を作成するには幾つかの方法があります。波かっこにキーと値を直接書く方法もあれば、dict関数を使う方法もありますし、辞書内包表記を使ってもよいでしょう。では、この場合はどんな方法が適していると思いますか? ちょっと考えてみてください。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「Pythonステップアップクイズ」のインデックス

連載目次

もっとカンタンに書けるよ!
もっとカンタンに書けるよ!

【問題】

 以下は2つのリストnamesとranksから辞書を作成するコードだ。各リストの同じインデックス位置にある要素がキーとその値となる(namesの要素がキーに、ranksの要素が値になる)。以下のコードではfor文を使って辞書を作成しているが、もっとシンプルに書ける。どうすればよいだろう。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = {}
for name, rank in zip(names, ranks):
    result[name] = rank

print(result)
# 出力結果:
# {'hp_kawasaki': 'C', 'isshiki': 'B', 'endo': 'A'}

もっとカンタンに書けるよ!

シンプルなのはどっち?

 以下では正解例の候補として筆者は2つの方法を考えています。そこで、ChatGPT(GPT-5.1)とGemini(Gemini 3のThinkingモード)、Claude(Opus 4.1)に問題文のコードの「よりカンタンに書き直してください」とお願いしてみました。3つのLLMはどんなコードを提案してきたのでしょうか。答えは最後に!



かわさき

 どうもHPかわさきです。

 いやー、寒くなってきましたねぇ。寒くなってくると腰痛もひどくなってきます。毎日、腰の痛みと闘いながら椅子に座っています。寝ているのが一番カンタンなんですが、原稿を書くにはやはり椅子に座ることになるんですよね。世にはスタンディングデスクなんてものもありますけれど、ずっと立っていると、それはそれで腰が痛くなるだろうし、何とかなりませんかね? 取りあえずは、週一でスーパー銭湯にでもいくことにしますか(ホントは毎日でもいきたいけれど……)。


【答え】

  正解のコード例を以下に示します。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = dict(zip(names, ranks))

print(result)

dict関数を使うのが一番カンタン(かな?)

 正解のコード例としてはdict関数を使うものとしました。zip関数に2つのリストを渡すことで、2つの要素で構成されるタプルを反復するイテレータが作成されます。これをdict関数に渡すことで、タプルの1つ目の要素をキーと、2つ目の要素を値とする辞書の要素が作成されます。

dict関数を使うのが一番カンタン(かな?)
dict関数を使うのが一番カンタン(かな?)

 辞書内包表記を使っても同じことが可能です。というか、「辞書内包表記を使うでしょ」と多くの方が考えたのではないでしょうか。でも、このような場合にはdict関数を使うのが一番カンタンでしょう。

【解説】

 問題文のコードは以下の通りです。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = {}
for name, rank in zip(names, ranks):
    result[name] = rank

print(result)

問題文のコード(再掲)

 これをdict関数を使って書き直したもの(正解例のコード)が以下です。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = dict(zip(names, ranks))

print(result)

dict関数なら1行で簡潔に書ける

 ただし、dict関数の振る舞いについて知っていないと、このコードの意味が見えないかもしれません。dict関数は反復可能オブジェクトを受け取り、それを基に辞書を作成できますが、これには条件があります。つまり、その反復可能オブジェクトの要素が「2つの要素で構成される反復可能オブジェクトである」必要があります。簡単にいうと「[(key1, value1), (key2, value2), ……]」のようなものを渡すと、そこから辞書を作ってくれるということです。このときには、2つの要素で構成される反復可能オブジェクトの1つ目の要素がキーに、2つ目の要素がそのキーの値になります(今の例なら{key1: value1, key2: value2}という辞書が作成されます)。

 ちょっと上のコードを分解してみましょう。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

tmp = zip(names, ranks)
tmp = list(tmp)
print(tmp)  # [('hp_kawasaki', 'C'), ('isshiki', 'B'), ('endo', 'A')]
result = dict(tmp)

print(result)

zip関数は引数として受け取った反復可能オブジェクトの同じインデックス位置にある要素を組み合わせてタプルとして反復する

 上のコードではまずzip関数に2つのリスト(namesとranks)を渡した結果を変数tmpに代入しています。zip関数は引数として受け取った反復可能オブジェクトの同じインデックス位置にある要素を組み合わせたタプルを反復するイテレータを返します。そのため、上のコードではlist関数を使って、それをリストに変換しています。できたリストは[('hp_kawasaki', 'C'), ('isshiki', 'B'), ('endo', 'A')]のように2つの要素で構成されるタプルを要素とするリストです。

 これをdict関数に渡せば、タプルの1つ目の要素(namesの各要素)をキーとして、2つ目の要素(ranksの各要素)をその値とする辞書が出来上がるというわけです。

 dict関数といえば「dict(foo='FOO', bar='BAR')」のような使い方をつい考えてしまうかもしれませんが、このような呼び出し方もあるんだということは覚えておきましょう。2つの反復可能オブジェクトから辞書を作るだけならこれが一番よいでしょう。

 では、もう一つの正解例の候補と筆者が考えた辞書内包表記を使うとしたら、どんなコードになるでしょう。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = {k: v for k, v in zip(names, ranks)}

print(result)

辞書内包表記を使うように書き直したコード

 for文を使うよりもシンプルになっているし、何をしているかについてもdict関数よりも明瞭といえます。zip関数を使うのはdict関数と(問題文のコードとも)一緒です。zip関数で2つのリストの要素を反復して、それをkとvに代入し、そこからkをキー、vをその値とする辞書の要素を作り出していることが一目瞭然です。そういう意味では可読性が高いのはこちらという考え方もできるでしょう。

 dict関数は(その振る舞いをちゃんと理解していれば)シンプルで分かりやすく、タイプ量も少なくて済みます。辞書内包表記はfor文の内容を1行に簡潔にまとめて、その意味も分かりやすいのですが、タイプ量はdict関数と比べるとちょっと多めです。

 というわけで、タイプ量の少なさとコードの簡潔さに重きを置いて、ここではdict関数を使う方法を正解例としています(異論は認めましょう。辞書内包表記って見やすいですもんね)。

 では、辞書内包表記はどういうところで便利に使えるのでしょう。キーや値を加工したいというときには、こちらを使うのが最適といえるでしょう。以下に例を示します。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = {k: ord(v) - ord('A') for k, v in zip(names, ranks)}

print(result)

ランクを0から2に変更して辞書を作成

 この例は'A'ランクを0、'B'ランクを1、'C'ランクを2とした辞書を作成するものです。dict関数でこれと同じことをしようとすると例えばこんなコードになるでしょう。

names = ['hp_kawasaki', 'isshiki', 'endo']
ranks = ['C', 'B', 'A']

result = dict(zip(names, [ord(r) - ord('A') for r in ranks]))

print(result)

加工した値をdict関数に渡そうとすると大変なことになる

 namesの要素とranksの要素を加工したものを要素とする反復可能オブジェクトをzip関数にまとめようとするだけでかなり面倒なことになってしまいます。このような場合は辞書内包表記を使うのが自然です。

 まとめるとこんな感じでしょうか。

  • 2つのリストから単純に辞書を作成する:dict関数
  • キーや値を加工したい:辞書内包表記
  • 可読性を重視するなら:辞書内包表記
  • 短く簡潔にしたいなら:dict関数

 dict関数と辞書内包表記にはそれぞれにメリットとデメリットがあります。それぞれのよさを引き出すように使うことをオススメします。


かわさき

 というわけで、3つのLLMが提案してきたコードは次のようになりました。

  • dict関数を使う方法:ChatGPTとGemini
  • 辞書内包表記を使う方法:Claude

 とはいえ、Claudeさんは辞書内包表記を使う方法について「最も簡潔」といいながら、その後でdict関数を使う方法について「最もシンプルで読みやすい」とも表しています。どっちなんだい? と聞きたくもなりますが、ここではあえて分断を狙い、Claudeさんは辞書内包表記を使う方法を提案したことにします(その後のやりとりではdict関数がシンプルであることにも同意してくれましたよ)。

 ちなみにChatGPTさんは2つの方法を提案して、dict関数が一番シンプルだといっていますが、Geminiさんはdict関数だけを提案して、「条件付きで辞書を作りたい場合は辞書内包表記もあるよ」というお答えになっています。

 dict関数に限らず、組み込み関数のシグネチャ(呼び出し方)をしっかり勉強しておくと、普段は気付かないかもしれない効率的なコードの書き方を考えつくかもしれませんね。


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

Pythonステップアップクイズ

Copyright© Digital Advantage Corp. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る