Pythonのf文字列って使いやすいじゃないですか。ついつい使っちゃいますよね。でも、f文字列が適していない場合もあるんです。そこがformatメソッドの出番なんですよね。
以下のmake_greeting関数はlangに受け取った言語コードに合わせて、f文字列にnameの値を埋め込んだものを返す。これは問題なく動作するが、対応する言語コードが増えるとif文がどんどん長くなっていく(出力を見ると言語コードに'fr'を渡したときにはelse節が実行されている)。文字列のformatメソッドを使って、よりシンプルに書き直してみよう。
def make_greeting(lang, name):
if lang == 'ja':
return f'こんにちは {name}さん'
elif lang == 'es':
return f'Hola {name}'
... # 他にもelif節がたくさん
else:
return f'Hello {name}'
greeting = make_greeting('ja', 'kawasaki')
print(greeting) # こんにちは kawasakiさん
greeting = make_greeting('fr', 'kawasaki')
print(greeting) # Hello kawasaki
というわけで、今回は問題文のコードをChatGPT(GPT-5.1)とGemini(Gemini 3。最初は思考モードで途中から高速モード)、Claude(Opus 4.5)の3つのLLMに見せて、「よりシンプルに書き直せますか?」と聞いてみました。彼らは正解例のコードを生成できたのでしょうか?
どうもHPかわさきです。
突然に寒くなってきましたよね。そうなると、湯豆腐の季節だと思いませんか? 筆者は先日、京都まで湯豆腐を食べにいってきました。嵐山の方です。竹林の小道で熊に遭遇したらどうしようとドキドキしていたのですが、熊が割って入る隙がないくらいに人が多かったですねぇ。湯豆腐は大変おいしゅうございました。来年は南禅寺の方で湯豆腐を食べたいと思います(小学生の日記か)。お土産代わりに湯豆腐を一人で食べた写真を置いておきますね。
正解のコード例を以下に示します。
TEMPLATES = {
'ja': 'こんにちは {name}さん',
'es': 'Hola {name}',
# 他にも各国語に対応した「テンプレート」がたくさん
'en': 'Hello {name}',
}
def make_greeting(lang, name):
template = TEMPLATES.get(lang, TEMPLATES['en'])
return template.format(name=name)
greeting = make_greeting('ja', 'kawasaki')
print(greeting) # こんにちは kawasakiさん
greeting = make_greeting('fr', 'kawasaki')
print(greeting) # Hello kawasaki
ここではTEMPLATESという辞書を作成して、言語コードをそのキーに、名前を埋め込む対象の文字列をその値としています。この文字列はf文字列ではなく、単純な文字列ですが、置換フィールド「{name}」を持っています。make_greeting関数ではgetメソッドを使って言語コードに対応する文字列をTEMPLATESから取得します。そして、その文字列のformatメソッドで置換フィールドにnameの値を埋め込むことにしました。こうすることで、make_greeting関数がスッキリと書けるようになりました。
問題文のコードは次のようなものでした。
def make_greeting(lang, name):
if lang == 'ja':
return f'こんにちは {name}さん'
elif lang == 'es':
return f'Hola {name}'
... # 他にもelif節がたくさん
else:
return f'Hello {name}'
greeting = make_greeting('ja', 'kawasaki')
print(greeting) # こんにちは kawasakiさん
greeting = make_greeting('fr', 'kawasaki')
print(greeting) # Hello kawasaki
このコードはシンプルで分かりやすいのですが、対応する言語コードが増えるとelif節の数もどんどん増えていくのが厄介です。そんなときには辞書を使うと、少しはコードがシンプルになります。f文字列を使ったまま、辞書バージョンのコードを書いてみましょう。
def make_greeting(lang, name):
GREETINGS = {
'ja': f'こんにちは {name}さん',
'es': f'Hola {name}',
# 他にも各国語に対応した挨拶文がたくさん
'en': f'Hello {name}',
}
greeting = GREETINGS.get(lang, GREETINGS['en'])
return greeting
greeting = make_greeting('ja', 'kawasaki')
print(greeting) # こんにちは kawasakiさん
greeting = make_greeting('fr', 'kawasaki')
print(greeting) # Hello kawasaki
このバージョンでは、辞書の値をf文字列として関数が受け取ったnameをそこに埋め込んでいます。そして、getメソッドで言語コードに対応した「nameが埋め込まれた後」のf文字列を1つだけ取得して、それを戻り値にしています。
このコードでもif文がなくなって、構造的にはスッキリしました。でも、関数呼び出しのたびにGREETINGSという辞書が作られて、その辞書の値でf文字列にnameの値が埋め込まれます。これってちょっと無駄じゃないですか? というのは、使われるf文字列は1つだけなのに、全ての言語のためにf文字列で文字列補完が行われるからです。
それは関数の外に出せばいいじゃない? と思うかもしれません。こんな感じですね。
GREETINGS = {
'ja': f'こんにちは {name}さん',
'es': f'Hola {name}',
# 他にも各国語に対応した挨拶文がたくさん
'en': f'Hello {name}',
}
def make_greeting(lang, name):
greeting = GREETINGS.get(lang, GREETINGS['en'])
return greeting
でも、これはダメなのです。f文字列は評価される時点で埋め込むためのオブジェクトがなければ、NameError例外が発生してしまうからです。上の例ではnameが何かが分かりませんから、NameError例外が発生してしまうでしょう(手元で試したら発生しました)。
このように「文字列をテンプレートとして、後からそこに何かを埋め込みたい」ときにはf文字列はあまりうまくありません。むしろ、正解例のコードで見せたように、単純な文字列をテンプレートとして、そのformatメソッドを使った方がよいでしょう。
TEMPLATES = {
'ja': 'こんにちは {name}さん',
'es': 'Hola {name}',
# 他にも各国語に対応した「テンプレート」がたくさん
'en': 'Hello {name}',
}
def make_greeting(lang, name):
template = TEMPLATES.get(lang, TEMPLATES['en'])
return template.format(name=name)
greeting = make_greeting('ja', 'kawasaki')
print(greeting) # こんにちは kawasakiさん
greeting = make_greeting('fr', 'kawasaki')
print(greeting) # Hello kawasaki
これなら辞書の作成は関数外で一度だけで済みますし、必要のない文字列へのnameの値の埋め込みも行わずに済みます。最初はf文字列を使ったバージョンでもいいかなと思いましたが、そんなところを考慮するとformatメソッドを使うバージョンの方が無駄がないコードだと思います。といっても、筆者自身はどうかというと、普通に問題文のコードを書いちゃうわけですが……(笑)。まあ、f文字列が便利過ぎて、普段はついそれ任せにしてしまうのですが、そうでもない場合もあることを覚えておきましょう。
なお、このようなif文を辞書(マップ)で置き換えることを「条件ロジックの辞書/マップでの置き換え」のように表現することもあり、リファクタリングではよくあるパターンともいえます。if文がかなり長くなってきたら「そんな方法もあったな」と思い出せるようにしておくとよいでしょう。
3つのLLMに「よりシンプルに書き直せますか?」と聞いて、最初に出てきたコードがどんなものだったのかを以下に列挙します。
3つのLLMにはあえて「formatメソッドを使って」という部分を省いて聞いてみました。それでも、3つのLLM全てがformatメソッドを使ったバージョンを生成してくれました。ただし、Claudeさんは同時にf文字列と辞書を使ったバージョンも生成して、そちらがイチオシとなっていました(その後、formatメソッドの方がよくない? と聞いたら同意してくれましたけど、LLMってそういうものよね)。例えば、以下はGeminiさんが生成してくれたコードです。
def make_greeting(lang, name):
templates = {
'ja': 'こんにちは {}さん',
'es': 'Hola {}',
# ここに 'fr': 'Bonjour {}' などを簡単に追加可能
}
fmt = templates.get(lang, 'Hello {}')
return fmt.format(name)
置換フィールドに名前がないのですが、これはformatメソッドで埋め込む値が1つだけだからでしょう。複数あれば、きっと置換フィールドに名前を付けてくれたはず。
気になるのは、3つのLLMの全てが辞書を外出しにはしてくれなかったところですかね(もちろん、外出しの方がよくない? と聞けば「鋭いご指摘ですね」と帰ってくるわけですが)。ま、これについても指摘をしたら、皆さん、その通りにしてくれました。
というわけで、LLMは一発で最適な答えを出してくれるとは限らないってことが今回もよく分かりました(笑)。
Copyright© Digital Advantage Corp. All Rights Reserved.