Pythonで文字列を扱う際には、ただつなげるだけでなく、変数の値を埋め込んで読みやすく整形することがとても重要です。
本記事では、古くからある%演算子と、より柔軟なstr.formatを中心に、文字列フォーマットの基礎から実践的な使い分けまで、図解を交えながら丁寧に解説します。
Pythonの文字列フォーマットとは
文字列フォーマット(formatting)の基本概念

プログラムでは、数値や文字列、日付などさまざまなデータを扱いますが、そのままの形では人間にとって読みづらいことが多いです。
そこで重要になるのが文字列フォーマット(文字列整形)です。
文字列フォーマットとは、テンプレートとなる文字列の中にプレースホルダを用意し、そこに変数の値を埋め込んで1つの見やすい文字列を作る仕組みを指します。
たとえばレポートのタイトル、ログ出力、集計結果の表示など、さまざまな場面で使われます。
単に"名前: " + name + ", 年齢: " + str(age)のように文字列結合する方法もありますが、変数が増えると可読性が急速に下がります。
フォーマット機能を使うと、テンプレートとデータをきれいに分離でき、後からの修正や翻訳にも対応しやすくなります。
Pythonで使われる主なフォーマット方法の種類

Pythonでは、主に次の3種類の文字列フォーマット方法が使われています。
- %演算子によるフォーマット
もっとも古くから存在する方法で、C言語のprintfとよく似た記法です。レガシーコードで見かけることが多く、今でも簡単な用途には使われます。 - str.formatメソッドによるフォーマット
Python 2.6/3.0で導入された方法で、波括弧{}を使った柔軟なフォーマットが可能です。位置引数・キーワード引数・オブジェクト属性など、さまざまな参照方法に対応しています。 - f文字列(f-strings)によるフォーマット
Python 3.6で導入された新しい方法で、文字列の前にfを付けて{式}を書くスタイルです。本記事の主題ではありませんが、実用上は現在もっとも推奨されることが多い方法です。
本記事では、この中でも%演算子とstr.formatに焦点を当て、書き方と特徴を詳しく見ていきます。
%演算子による文字列フォーマット
%演算子の基本構文と書き方

%cst-strong>%演算子による文字列フォーマットは、次のような構文で書きます。
# 単一の値を埋め込む例
name = "Alice"
message = "Hello, %s" % name
print(message)
Hello, Alice
フォーマット文字列の中に%sのような書式指定子を書き、その右側に% 値を続ける形です。
複数の値を埋め込みたい場合は、次のようにタプルを使います。
# 複数の値を埋め込む例
name = "Bob"
age = 30
message = "名前: %s, 年齢: %d" % (name, age)
print(message)
名前: Bob, 年齢: 30
このように左側にテンプレート文字列、右側にデータを置くことで、人間にもわかりやすい形で文字列を構築できます。
%s・%d・%fなどの書式指定子一覧

%cst-strong>書式指定子は、埋め込む値の型や表示形式を指定するためのミニ言語です。
代表的なものを表にまとめます。
| 分類 | 書式指定子 | 意味の概要 |
|---|---|---|
| 文字列 | %s | 文字列として表示(多くの型を自動で文字列化) |
| 文字列 | %r | repr()形式で表示(デバッグ向き) |
| 整数 | %d | 10進整数として表示 |
| 整数 | %i | %dとほぼ同じ(10進整数) |
| 整数 | %x | 16進数(小文字) |
| 整数 | %X | 16進数(大文字) |
| 整数 | %o | 8進数 |
| 浮動小数点 | %f | 固定小数点形式(デフォルト6桁) |
| 浮動小数点 | %.3f | 小数点以下3桁など、桁数指定と組み合わせて使用 |
| 浮動小数点 | %e | 指数表記(小文字) |
| 浮動小数点 | %E | 指数表記(大文字) |
| その他 | %% | リテラルの%cst-code>%を出力 |
たとえば、小数の桁数を指定したい場合は次のように書きます。
price = 123.456
# 小数点以下2桁に丸めて表示
text = "価格: %.2f 円" % price
print(text)
価格: 123.46 円
ここでは%.2fによって、浮動小数点を小数点以下2桁に整形しています。
また、幅やゼロ埋めを指定することもできます。
num = 42
# 幅5で右寄せ
print("番号: %5d" % num)
# 幅5でゼロ埋め
print("番号: %05d" % num)
番号: 42
番号: 00042
複数値をタプルで渡す例と注意点

複数の値を埋め込むときには、右側の値をタプルで渡すのが基本です。
x = 10
y = 20
name = "Alice"
# %演算子では、複数値はタプルで渡す
text = "x=%d, y=%d, name=%s" % (x, y, name)
print(text)
x=10, y=20, name=Alice
ここで重要なのは、左側の書式指定子の数と右側の値の数が一致している必要があるという点です。
数が合わないとTypeErrorになります。
# 書式指定子は2つなのに、値が1つしかない誤った例
template = "x=%d, y=%d"
x = 10
# 下の行はエラーになります
# text = template % x
また、右側にタプルを渡すべきところでリストを渡しても動きますが、慣習的にはタプルが使われます。
辞書を使って名前付きで埋め込むことも可能ですが、書き方が少し変わります。
data = {"name": "Bob", "age": 25}
text = "名前: %(name)s, 年齢: %(age)d" % data
print(text)
名前: Bob, 年齢: 25
このように、%(name)sのように辞書のキー名をカッコ内に書くことで、位置ではなく名前で値を指定できます。
%演算子のメリット・デメリット

%cst-strong>%演算子には、次のような特徴があります。
メリットとしては、まず記法が短くシンプルであることが挙げられます。
特に、単純な1〜2個の値を埋め込むだけなら直感的に書けます。
また、C言語のprintfスタイルになじみがある方には覚えやすく、古いPythonコードとの互換性も高いです。
一方でデメリットとして、複雑なフォーマットになると可読性が急激に下がることが挙げられます。
タプルの順番に強く依存するため、あとから項目を追加・削除する際にミスが起きやすくなります。
また、辞書やオブジェクトの属性にアクセスする表現力が弱く、型に応じて正しい書式指定子を選ぶ必要があるため、初心者がつまずきやすい面もあります。
現在のPythonでは、新規コードでの常用はあまり推奨されず、後述するstr.formatやf文字列が好まれます。
ただし、既存のコードを読む・メンテナンスするためには理解しておくことが重要です。
str.formatによる文字列フォーマット
str.formatの基本構文と位置引数・キーワード引数

str.formatは、文字列オブジェクトのメソッドとして提供されるフォーマット方法です。
基本構文は次のようになります。
name = "Alice"
age = 20
# 位置引数を使った例
text1 = "名前: {}, 年齢: {}".format(name, age)
print(text1)
# キーワード引数を使った例
text2 = "名前: {n}, 年齢: {a}".format(n=name, a=age)
print(text2)
名前: Alice, 年齢: 20
名前: Alice, 年齢: 20
位置引数では、{}のプレースホルダに、formatメソッドに渡した引数が順番通りに入ります。
キーワード引数では、{n}のように名前を付け、その名前と同じキーワード引数をformatに渡します。
位置を数字で明示的に指定することもできます。
text = "{1}さんと{0}さん".format("太郎", "花子")
print(text)
花子さんと太郎さん
このように{1}や{0}と番号を振ることで、引数の順番を自由に入れ替えて表示できます。
{ }(波括弧)の書式指定ミニ言語の使い方

str.formatでは、プレースホルダの中に{フィールド名:書式指定}という形で、さらに詳細な指定を行えます。
value = 123.456
text = "値は {0:.2f} です".format(value)
print(text)
値は 123.46 です
この{0:.2f}の構造を分解すると次のようになります。
0: 1番目の引数(位置引数のインデックス):: フィールド名と書式指定の区切り.2f: 「小数点以下2桁の浮動小数点」という書式指定
フィールド名には、数字のインデックスだけでなく、キーワード名やオブジェクトの属性、さらには辞書のキーなども指定できます。
書式指定の部分には、数値の桁数、整列方法、埋め文字、通貨表記など、さまざまなオプションを組み合わせることができます。
数値フォーマット(桁数・ゼロ埋め・小数点)の指定

数値のフォーマットには幅指定・ゼロ埋め・小数点桁数・カンマ区切りなど、実用的なオプションがたくさんあります。
代表的な例を見てみます。
num = 42
pi = 3.14159265
big = 1234567
# 幅を指定(右寄せ)
print("num = {:5d}".format(num)) # 幅5
# 幅を指定(ゼロ埋め)
print("num = {:05d}".format(num)) # 幅5、ゼロ埋め
# 小数点以下の桁数を指定
print("pi = {:.2f}".format(pi)) # 小数点以下2桁
# カンマ区切り + 小数点以下指定
print("big = {:,.2f}".format(big)) # 3桁ごとにカンマ
num = 42
num = 00042
pi = 3.14
big = 1,234,567.00
ここで使われている書式指定の一般形は、次のように考えると整理しやすいです。
| 要素 | 例 | 意味 |
|---|---|---|
| フィル文字 | 0, 空白 | 空きを何で埋めるか |
| 配置 | <, >, ^ | 左寄せ・右寄せ・中央寄せ |
| 符号 | +, -, 空 | 符号の表示方法 |
| 幅 | 10など | 全体の幅 |
| カンマ | , | 3桁ごとの区切り |
| 精度 | .2 | 小数点以下の桁数など |
| 型 | d, f, xなど | 整数・浮動小数点・16進数など |
これらを組み合わせて1つの{:書式指定}を作ります。
たとえば{:0>8.2f}なら、「ゼロ埋め・右寄せ・幅8・小数点以下2桁・浮動小数点」という意味になります。
value = 12.3
print("{:0>8.2f}".format(value))
00012.30
文字列整形(左寄せ・右寄せ・中央寄せ)の指定

str.formatでは、文字列の整列(左寄せ・右寄せ・中央寄せ)も簡単に指定できます。
text = "ABC"
# 左寄せ(幅10)
print("左寄せ : '{:<10}'".format(text))
# 右寄せ(幅10)
print("右寄せ : '{:>10}'".format(text))
# 中央寄せ(幅10)
print("中央寄せ: '{:^10}'".format(text))
左寄せ : 'ABC '
右寄せ : ' ABC'
中央寄せ: ' ABC '
さらに、空きを埋める文字を指定することもできます。
たとえば、ハイフンで埋めたい場合は、フィル文字を先頭に書きます。
title = "Title"
print("{:-^20}".format(title))
-------Title-------
ここでは:-^20によって、「フィル文字-」「中央寄せ^」「幅20」という指定を同時に行っています。
辞書やオブジェクトを使ったformatの例

str.formatの大きな強みは、辞書やオブジェクトと相性が良いことです。
まずは辞書の例です。
person = {"name": "Alice", "age": 20}
# **person で辞書を展開してキーワード引数として渡す
text = "名前: {name}, 年齢: {age}".format(**person)
print(text)
名前: Alice, 年齢: 20
**personによって辞書を展開し、そのキーをキーワード引数として渡しています。
テンプレート側では{name}や{age}と、キー名をそのまま使えるので、順番に依存しない読みやすいフォーマットが実現できます。
次にオブジェクトの属性を参照する例です。
class User:
def __init__(self, name, score):
self.name = name
self.score = score
user = User("Bob", 95)
# 引数userの属性にドットでアクセス
text = "ユーザー: {u.name}, スコア: {u.score}".format(u=user)
print(text)
ユーザー: Bob, スコア: 95
ここでは{u.name}や{u.score}のようにドット記法を使うことで、オブジェクトの属性に自然にアクセスしています。
このような記述は、ログやテンプレートの出力で特に便利です。
辞書やリストを直接フィールド名として書くこともできます。
data = {"x": 10, "y": 20}
text = "x={d[x]}, y={d[y]}".format(d=data)
print(text)
x=10, y=20
このように{d[x]}と書くことで、辞書dのキーxに対応する値を参照できます。
str.formatのメリット・デメリット

str.formatには、次のようなメリットがあります。
まず、柔軟で表現力が高いことです。
位置引数・キーワード引数・属性参照・辞書参照など、さまざまな方法で値を指定できます。
また、書式指定ミニ言語により、数値や文字列の細かな整形が可能です。
テンプレート文字列を1つ用意しておき、異なるデータを繰り返し埋め込むようなケースでも、可読性の高いコードを書けます。
一方でデメリットとしては、記述がやや冗長になりがちな点が挙げられます。
特にPython 3.6以降では、同様のことをより簡潔に書けるf文字列が登場したため、日常的なコードではf文字列が優先される場面が増えています。
それでも、テンプレート文字列を外部ファイルや設定として持つといった場面ではstr.formatが今も有力な選択肢です。
f文字列はリテラル文字列限定ですが、formatは任意の文字列に対して実行できる、という違いも覚えておくと便利です。
%演算子 vs formatの比較と使い分け
%演算子とformatの記述性・可読性を比較
同じ仕事を%cst-strong>%演算子とstr.formatで書いた場合の違いを、実際のコードで比べてみます。
name = "Alice"
age = 20
# %演算子
text_percent = "名前: %s, 年齢: %d" % (name, age)
# str.format(キーワード引数)
text_format = "名前: {name}, 年齢: {age}".format(name=name, age=age)
print(text_percent)
print(text_format)
名前: Alice, 年齢: 20
名前: Alice, 年齢: 20
この例では、%演算子の方が短いですが、str.formatの方はプレースホルダに意味のある名前が付いています。
そのため、テンプレート文字列だけを見ても、「ここにはnameという値が入る」「ここにはageという値が入る」と一目で分かります。
項目が増えてくると、その差はさらに大きくなります。
# %演算子
log_percent = "[%s] user=%s, action=%s, status=%d" % (timestamp, user, action, status)
# str.format
log_format = "[{time}] user={user}, action={action}, status={status}".format(
time=timestamp, user=user, action=action, status=status
)
後者の方が順番に依存せず、項目の追加・削除もしやすいため、保守性が高いコードになります。
処理速度(パフォーマンス)の違い

パフォーマンスについては、状況やPythonバージョンによって変動しますが、一般的には次のような傾向があります。
- f文字列: もっとも高速であることが多い
- %演算子: 比較的速い
- str.format: 柔軟な分だけ、やや遅いことが多い
ただし、通常のアプリケーション開発では、この差がボトルネックになることはまれです。
大量のログを高頻度で生成するような特殊なケースを除けば、可読性や保守性を優先して選ぶのがよいでしょう。
どうしても気になる場合は、自分の環境と実際の処理内容でtimeitモジュールを使って計測してみるとよいです。
import timeit
code_percent = '"名前: %s, 年齢: %d" % ("Alice", 20)'
code_format = '"名前: {}, 年齢: {}".format("Alice", 20)'
t_percent = timeit.timeit(code_percent, number=100000)
t_format = timeit.timeit(code_format, number=100000)
print("%%演算子 :", t_percent)
print("format :", t_format)
%演算子 : 0.0xxx
format : 0.0yyy
(実際の数値は環境により異なりますが、目安としての比較になります。)
Pythonのバージョン別の推奨スタイル

Pythonのバージョンごとに、文字列フォーマットの推奨スタイルも変化してきました。
- Python 2.x
歴史的には%演算子が主に使われていましたが、2.6からstr.formatが導入され、徐々に移行が進みました。 - Python 3.0〜3.5
公式ドキュメントでもstr.formatが推奨され、%演算子はレガシー寄りの位置付けになりました。 - Python 3.6以降
f文字列が登場し、多くのケースで第一候補となりました。ただし、テンプレートとしての柔軟性が必要な場面では、引き続きstr.formatも現役です。
新規開発でPython 3.6以上が前提であれば、普段使いにはf文字列、高度なテンプレート処理や外部から読み込む書式文字列にはstr.format、という使い分けが現実的です。
%演算子は主に既存コードの読解や軽量な用途に限定するとよいでしょう。
どちらを使うべきかの判断基準と実践的な使い分け

実際に「どちらを使うべきか」を判断する際のポイントを、いくつかの観点から整理します。
- Pythonのバージョン
Python 3.6以上であれば、基本的にはf文字列 + str.formatを組み合わせる形で設計し、%演算子は最小限に留めるのがよいです。Python 2系までを含むレガシー環境では、str.formatを優先しつつ、必要に応じて%演算子も使われます。 - テンプレートの性質
コードの中に直接書く短い文字列であれば、%演算子でもstr.formatでも書けますが、可読性・拡張性を考えるとstr.formatの方が有利です。外部ファイルや設定でテンプレートを持ち、そこにデータを流し込むような仕組みでは、str.format一択と考えてよいでしょう。 - データの構造
辞書やオブジェクトを扱う場合は、str.formatの方が圧倒的に書きやすくなります。キー名や属性名をそのままテンプレートに書けるため、ログやエラーメッセージのフォーマットにも向いています。 - チームやプロジェクトのコーディング規約
プロジェクトによっては「新規コードでは%演算子禁止」「文字列フォーマットは原則f文字列」といったルールを定めている場合もあります。こうした場合でも、既存コードの理解や修正のために%演算子とstr.format双方を理解しておくことが重要です。
実践的なまとめとしては、次のような方針が取りやすいです。
- Python 3.6以上の新規コード
- 日常的なフォーマット: f文字列
- テンプレート文字列(外部ファイルなど): str.format
- %演算子: 原則として新規使用は控える
- 既存コード・レガシー環境の対応
- %演算子で書かれたコードを読めるようにしておく
- 大規模な修正時には、可能であればstr.formatやf文字列への移行を検討する
まとめ
Pythonの文字列フォーマットは、%演算子とstr.format、そしてf文字列という3つの手段があり、それぞれに歴史的背景と得意分野があります。
%演算子は短く書ける反面、複雑になると可読性に難があり、現代のPythonでは主に既存コードで見かける存在です。
一方、str.formatは柔軟で表現力が高く、辞書やオブジェクトと組み合わせる場面でも力を発揮します。
Python 3.6以降ではf文字列が日常使いの第一候補となりますが、テンプレートとしての利用や外部ファイルとの連携では今もstr.formatが有用です。
この記事で紹介した特徴と使い分けの基準を押さえれば、状況に応じて最適なフォーマット方法を選び、読みやすく保守しやすいコードを書けるようになります。
