Pythonでは数値や文字列を見やすく整形して出力するために、いくつかの文字列フォーマット手段が用意されています。
本記事では、昔ながらのフォーマットである%演算子とstr.format
メソッドの2つに絞って、基本からよくある落とし穴まで丁寧に解説します。
他の文字列操作は別記事で扱います。
Pythonの文字列フォーマットの基本
文字列フォーマットの目的
文字列フォーマットは、値を埋め込みながら見やすく整形して表示したり、ログメッセージやファイル出力の体裁を揃えたりするために使います。
数値の桁数をそろえる、小数点以下の桁数を制御する、符号を明示する、単位を付ける、桁区切りを入れるなど、読み手に優しい表現を実現できます。
2つの方法 %演算子とformatメソッド
Pythonには歴史的に2つの主要なやり方があります。
- %演算子(旧式フォーマット):
"Hello %s" % name
のように、C言語のprintf
に似た記法です。短く書ける反面、複雑になると読みにくくなりがちです。 str.format
メソッド(新式フォーマット):"Hello {}".format(name)
のように、{}
に置換フィールドを置く方法です。整形ルールが強力で、読みやすくメンテナンスしやすいのが特徴です。
本記事はこの2つに絞ります(近年主流のf-stringは本記事の対象外です)。
書式指定の基本ルール
どちらの記法も「プレースホルダ(置換フィールド)+書式指定子」という構造を持ちます。
大枠の違いと対応関係は次のとおりです。
要素 | %演算子の例 | formatの例 | 意味 |
---|---|---|---|
プレースホルダの形 | %s , %d , %.2f | {} , {:d} , {:.2f} | 値の差し込み位置と型/書式を示します |
複数値の渡し方 | タプル% (a, b) 、辞書% {"x": 1} | 位置/名前で.format(a, b) 、.format(x=1) | どの値をどこに入れるか指定します |
幅 | %8d | {:8d} | 出力の全体幅(桁)を指定します |
精度 | %.3f , %.3s | {:.3f} , {:.3s} | 小数桁/文字列の最大長などを制御します |
整列 | %-8s (左) | {:<8} , {:>8} , {:^8} | 左右中央寄せを指定します |
符号 | %+d | {:+d} , {: d} , {-d} | プラスを明示、空白符号などを指定します |
ゼロ埋め | %08d | {:08d} | 幅をゼロで満たします |
桁区切り | (直接は不可) | {:,d} , {:,.2f} | 3桁区切り(,)を付けます |
表の各要素は以下の章で詳しく実例を示します。
%演算子の使い方
基本の%s %d %f
%sは文字列、%dは整数、%fは浮動小数点数を表します。
小数点以下の桁数は%.2f
のように指定します。
# 基本の%s、%d、%f
name = "Alice"
age = 23
score = 95.5
pi = 3.14159
print("name=%s age=%d score=%.1f pi=%.2f" % (name, age, score, pi))
# 複数値: タプル
msg1 = "Hello %s, you have %d messages" % (name, 5)
# 複数値: 辞書
template = "%(user)s has %(n)d new messages (user=%(user)s)"
msg2 = template % {"user": name, "n": 5}
print(msg1)
print(msg2)
name=Alice age=23 score=95.5 pi=3.14
Hello Alice, you have 5 messages
Alice has 5 new messages (user=Alice)
複数値 タプルと辞書
複数の値を埋め込むときは、タプルで渡すのが基本です。
読みやすさを高めたいときや同じ値を複数回使うときは、%(name)s
のような名前付きプレースホルダと辞書を使います。
辞書は必須のキーが欠けているとKeyError
になるため注意します。
幅 精度 符号 ゼロ埋め 左寄せ
見た目を整える要素は組み合わせて使えます。
# 幅(width)、精度(precision)、符号(sign)、ゼロ埋め(zero padding)、左寄せ
s = "py"
n = 123
neg = -7
f = 12.3456
print("[%10s]" % s) # 右寄せして全体幅10
print("[%-10s]" % s) # 左寄せして全体幅10
print("[%08d]" % n) # 桁数8にゼロ埋め
print("[%+08d]" % n) # +符号を付け、ゼロ埋め
print("[%+8d]" % neg) # 幅8で右寄せ(負数は-符号が付く)
print("[%10.2f]" % f) # 幅10、小数2桁に丸め
print("[%-10.2f]" % f) # 左寄せ
[ py]
[py ]
[00000123]
[+0000123]
[ -7]
[ 12.35]
[12.35 ]
ポイント
%8d
は右寄せ、%-8d
は左寄せです。
%08d
のように0を付けると、幅の不足分が0で埋まります(符号の直後からゼロが入ります)。
%.2f
は四捨五入されます。精度は浮動小数点の丸め誤差に注意してください。
数値の型 d x o e f g
数値をさまざまな表現に変換できます。
n = 255
f = 1234.56789
print("d=%d, x=%x, X=%X, o=%o" % (n, n, n, n)) # 10進, 16進(小/大), 8進
print("e=%.3e, E=%.3E" % (f, f)) # 指数表記(小/大)
print("f=%.2f, g=%.4g, G=%.4G" % (f, f, f)) # 固定小数, 汎用(小/大)
d=255, x=ff, X=FF, o=377
e=1.235e+03, E=1.235E+03
f=1234.57, g=1235, G=1235
%g
は値の大きさに応じて%f
か%e
を選び、有効桁数で丸めます。
進数表記に接頭辞を付けたいときの#
フラグはPython 3では%#x -> 0xff
、%#o -> 0o377
のように出力されます。
よくあるエラー
型や引数の数が合わないと例外になります。
実行時に気づけるよう、エラーメッセージを確認しましょう。
def show_err(label, fmt, value):
# %演算子のエラー表示を簡潔に行うヘルパ
try:
print(label, "=>", fmt % value)
except Exception as e:
print(label, "=>", type(e).__name__, "-", e)
show_err("型不一致", "count=%d", "10") # %dに文字列
show_err("引数不足", "Name=%s Age=%d", ("Alice",)) # 年齢が不足
show_err("辞書キー不足", "%(name)s is %(age)d", {"name": "Bob"})
show_err("未知の変換指定子", "%.2q", 12.3) # 存在しない型コード
型不一致 => TypeError - %d format: a number is required, not str
引数不足 => TypeError - not enough arguments for format string
辞書キー不足 => KeyError - 'age'
未知の変換指定子 => ValueError - unsupported format character 'q' (0x71) at index 3
formatメソッドの使い方
位置引数と名前付き引数
str.format
は{}
で置換フィールドを示します。
位置や名前で指定でき、順序の入れ替えや同じ値の再利用が簡単です。
name = "Alice"
print("Hello {}, you have {} messages.".format(name, 5)) # 自動番号
print("{1} then {0} then {1}".format("first", "second")) # 明示番号
print("Coordinates: lat={lat}, lon={lon}".format(lat=35.0, lon=139.0))# 名前付き
Hello Alice, you have 5 messages.
second then first then second
Coordinates: lat=35.0, lon=139.0
ポイント
自動番号{}
と手動番号{0}
は混在させないでください(エラーになります)。
名前付きは読みやすく、後から項目を追加しやすいです。
型 幅 精度 整列 埋め文字 桁区切り
{フィールド:書式指定}
のコロン右側に詳細なルールを書きます。
n = 12345
f = 12.3456
s = "py"
s2 = "Pythonic"
# 整列と埋め文字
print("[{:>10}]".format(s)) # 右寄せ
print("[{:<10}]".format(s)) # 左寄せ
print("[{:^10}]".format(s)) # 中央寄せ
print("[{:*^10}]".format(s)) # *で埋めながら中央寄せ
# 整数のゼロ埋めと符号
print("[{:08d}]".format(n)) # 幅8、ゼロ埋め
print("[{:+08d}]".format(n)) # 符号+、ゼロ埋め
print("[{:+8d}]".format(-n)) # 符号保持、空白埋め
# 浮動小数の精度と幅
print("[{:.2f}]".format(f)) # 小数2桁
print("[{:10.2f}]".format(f)) # 幅10、小数2桁(右寄せ)
# 文字列の最大長(切り詰め)
print("[{:.3s}]".format(s2)) # 先頭3文字のみ
# 桁区切りとパーセント
print("[{:,.2f}]".format(1234567.89)) # 3桁区切り
print("[{:.1%}]".format(0.256)) # パーセント(100倍+%)
[ py]
[py ]
[ py ]
[****py****]
[00012345]
[+0012345]
[ -12345]
[12.35]
[ 12.35]
[Pyt]
[1,234,567.89]
[25.6%]
基本形: {:[fill][align][sign][#][0][width][,][.precision][type]}
fill
は1文字の埋め文字、align
は<
(左)、>
(右)、^
(中央)です。
,
で3桁区切り、type
はd x X o b e E f F g G n % s
などを指定します。
辞書とformat_map
辞書そのものを渡すときはformat_map
が便利です。
キー不足時の扱いもコントロールしやすくなります。
from collections import defaultdict
user = {"name": "Alice", "age": 23}
tmpl = "{name} is {age} years old"
print(tmpl.format_map(user)) # そのまま辞書を渡す
# キー不足はKeyErrorになる
data = {"name": "Bob"}
try:
print(tmpl.format_map(data))
except KeyError as e:
print("KeyError:", e)
# デフォルト値で埋める(足りないキーは"N/A")
default_user = defaultdict(lambda: "N/A", data)
print(tmpl.format_map(default_user))
Alice is 23 years old
KeyError: 'age'
Bob is N/A years old
変換フラグ !s !r !a
置換フィールドの直後に!s
(str)、!r
(repr)、!a
(ascii)を付けると、どの文字列表現を使うか選べます。
デバッグ時に!r
は特に有用です。
class User:
def __init__(self, name):
self.name = name
def __str__(self):
# ユーザ向けの見やすい表現
return "<User {}>".format(self.name)
def __repr__(self):
# 開発者向けの詳細な表現
return "User(name={!r})".format(self.name)
u = User("Alice")
print("default: {}".format(u)) # 既定は__str__()
print("!s: {!s}".format(u)) # 明示的に__str__()
print("!r: {!r}".format(u)) # __repr__()
print("!a: {!a}".format("AΩ\n")) # 非ASCIIと制御文字をエスケープ
default: <User Alice>
!s: <User Alice>
!r: User(name='Alice')
!a: 'A\u03a9\n'
よくあるエラー
str.format
では、引数不足、キー不足、混在ルール違反、未知の型コードなどで例外が発生します。
def show_format_err(label, fmt, *args, **kwargs):
try:
print(label, "=>", fmt.format(*args, **kwargs))
except Exception as e:
print(label, "=>", type(e).__name__, "-", e)
show_format_err("引数不足", "{} {} {}", 1, 2) # 3つ必要だが2つしかない
show_format_err("キー不足", "{name} {age}", name="Bob") # ageがない
show_format_err("自動と手動の混在", "{0} {}", "A", "B") # 混在は禁止
show_format_err("未知の型コード", "{:q}", 10) # 存在しない型コード
引数不足 => IndexError - Replacement index 2 out of range for positional args tuple
キー不足 => KeyError - 'age'
自動と手動の混在 => ValueError - cannot switch from manual field specification to automatic field numbering
未知の型コード => ValueError - Unknown format code 'q' for object of type 'int'
使い分けとベストプラクティス
%演算子とformatメソッドの選び方
短いワンライナーや既存の古いコードを少し直す程度なら%演算子でも十分です。"id=%d" % n
のような単純な用途は読みやすく保てます。
複数の値を整形したり、幅・精度・桁区切り・整列などを組み合わせる場合はstr.format
を使うと読みやすくなります。名前付きフィールドで自己文書化でき、引数の順序入れ替えも容易です。
余談ですが、Python 3.6以降ではf-stringが最も推奨されます。本記事では扱いませんが、将来的にはf-stringの採用も検討すると良いでしょう。
読みやすい書き方のコツ
- 意味のある名前付きフィールドを使うと、テンプレート文字列だけで「何が入るか」分かります。
- 書式指定は「何を整形しているか」を優先し、複雑な式は先に変数に分解してから整形すると読みやすくなります。
- 数値の丸めは意図を明確に。金額など厳密な丸めが必要な場合は
decimal.Decimal
を使う設計を検討します。 - ログやユーザ向け表示は、桁区切り
{:,d}
やパーセント{:.1%}
などの読みやすい表現を活用します。
覚えておく書式パターン集
よく使うパターンは次の表を手元に置いておくと便利です。
目的 | %演算子 | formatメソッド | 値 | 出力例 |
---|---|---|---|---|
整数を8桁でゼロ埋め | %08d | {:08d} | 42 | 00000042 |
符号を常に表示 | %+d | {:+d} | 7 | +7 |
浮動小数を小数2桁 | %.2f | {:.2f} | 3.14159 | 3.14 |
幅10で左寄せ(小数2) | %-10.2f | {:<10.2f} | 12.3 | 12.30 |
16進(小文字) | %x | {:x} | 255 | ff |
16進(大文字) | %X | {:X} | 255 | FF |
指数表記 | %.2e | {:.2e} | 0.00123 | 1.23e-03 |
文字列を3文字に切り詰め | %.3s | {:.3s} | “abcdef” | abc |
3桁区切り | (なし) | {:,d} | 12345 | 12,345 |
名前付きで埋め込み | %(name)s is %(age)d | {name} is {age} | name=”Ann”, age=20 | Ann is 20 |
まとめ
%演算子とstr.format
はいずれも、値の可読性を高めて安全に表示するための強力な道具です。
%演算子は短く、単純な用途に向きます。
一方str.format
は、整列・幅・精度・桁区切り・名前付きフィールドなど、複雑な体裁を分かりやすく表現できます。
まずは基本の型指定(%s/%d/%f、{:d}/{:.2f}
)と、幅・精度・整列・符号・ゼロ埋めの5要素を押さえると実務の多くをカバーできます。
エラー時の挙動(引数不足や型不一致、フィールド番号の混在禁止など)も一通り確認しておけば、デバッグに強くなれます。
将来的にはf-stringも視野に入れつつ、本記事の内容を足掛かりに、目的に合ったフォーマットを選び分けていきましょう。