Pythonのf-string(f文字列)は、可読性と実用性を両立した現代的な文字列フォーマット機能です。
変数や式を{}に直接書けるため、文字列連結やformat()に比べて短く読みやすいコードになります。
本記事では基本から書式指定子、数値や日付の整形、応用テクニック、注意点までを段階的に解説します。
f-string(f文字列)の基本
f-stringとは(Python 3.6+)
f-stringはPython 3.6で導入された文字列リテラルで、冒頭にfまたはFを付け、文字列中の{}内にPythonの式を直接書けます。
評価結果がその場で埋め込まれるため、簡潔で読みやすいコードになります。
# f-stringの最小例
name = "Alice"
age = 20
msg = f"名前は{name}、年齢は{age}です"
print(msg)
名前はAlice、年齢は20です
基本構文(f”…{式}…”)
f"…{式}…"の形で、{}の中に有効なPython式を書けます。
変数名だけでなく、四則演算や関数呼び出しなども使えます。
# {} の中は式を書ける
a, b = 7, 3
print(f"{a} + {b} = {a + b}") # 式(加算)
print(f"平方は {b**2}") # べき乗
print(f"長さは {len('hello')}") # 関数呼び出し
7 + 3 = 10
平方は 9
長さは 5
- 関連記事:文字列の長さを調べる
変数と式の埋め込み
f-stringではstr()への明示的な変換が不要です。
複数の変数を自然に混在できます。
# 変数・式をそのまま埋め込む
user = "bob"
items = ["pen", "notebook"]
count = len(items)
print(f"{user}さんのアイテム数は{count}個({items})です")
bobさんのアイテム数は2個(['pen', 'notebook'])です
文字列と数値をそのまま結合
従来の"Hi " + name + " #" + str(n)のような書き方は不要です。
数値も{}に入れれば自動で文字列化されます。
name, n = "Carol", 42
print(f"Hi {name} #{n}")
Hi Carol #42
デバッグ出力(=)の使い方(Python 3.8+)
Python 3.8以降、{式=}で式と結果をペアで表示できます。
結果はrepr()で表現されます。
# デバッグに便利な = 指定子 (Python 3.8+)
path = "/usr/local/bin"
n = 5
print(f"{path=}, {n=}, {n*2=}")
path='/usr/local/bin', n=5, n*2=10
変換フラグ(!s !r !a)の違い
!sはstr()、!rはrepr()、!aはascii()で表示へ変換します。
デバッグには!rが役立ちます。
# 変換フラグの例
text = "こんにちは\n" # 改行を含む
print(f"デフォルト: {text}")
print(f"!s: {text!s}")
print(f"!r: {text!r}") # エスケープを含む表現
print(f"!a: {'αβ'!a}") # 非ASCIIを\x, \u などで表現
デフォルト: こんにちは
!s: こんにちは
!r: 'こんにちは\n'
!a: '\u03b1\u03b2'
波かっこを出力する({{ }})方法
文字通りの{/}を出力したい場合は二重の波かっこを使います。
# { と } を文字として出す
print(f"ブレースは {{ と }} です")
ブレースは { と } です
- 関連記事:文字列の結合と繰り返し
書式指定子(:)の基礎
書式の書き方({値:指定})
{値:指定}の形で整形ルールを与えます。
書式指定の構成は概ね次の順序です。
| 要素 | 意味 | 例 |
|---|---|---|
| [fill][align] | 埋め文字と配置 | _>10で右寄せを<em>_</em>で埋め |
| [sign] | 符号 | +, -, 空白 |
| [#] | 代替形式 | 基数接頭辞0xなど |
| [0] | 数値のゼロ埋め | 08 |
| [width] | 幅 | 10 |
| [grouping] | 桁区切り | , または _ |
| [.precision] | 精度 | .2 |
| [type] | 型 | d, f, x, % など |
# フォーマット指定の基本
x = 1234.5678
print(f"[{x:10.2f}]") # 幅10, 小数2桁
print(f"[{x:>10.2f}]") # 右寄せ
print(f"[{x:^10.2f}]") # 中央寄せ
[ 1234.57]
[ 1234.57]
[ 1234.57 ]
幅と配置(< > ^)で揃える
表形式の出力で整列に使います。
<(左寄せ)、>(右寄せ)、^(中央寄せ)です。
# 幅と配置
headers = ("item", "qty", "price")
rows = [("apple", 3, 120), ("banana", 10, 58), ("kiwi", 1, 240)]
print(f"{headers[0]:<10} {headers[1]:>5} {headers[2]:>8}")
for name, qty, price in rows:
print(f"{name:<10} {qty:>5d} {price:>8d}")
item qty price
apple 3 120
banana 10 58
kiwi 1 240
埋め文字とゼロ埋め(0)
任意の1文字で埋められます。
数値の左側を0で埋めるには0を使います。
# 埋め文字とゼロ埋め
n = 42
print(f"[{n:_>6}]") # '_'で右側に埋め
print(f"[{n:*^6}]") # '*'で中央寄せ
print(f"[{n:06}]") # 0埋め(幅6)
[____42]
[**42**]
[000042]
精度(.n)と丸め
小数の桁数を指定します。
fなら小数点以下の桁数、gなら有効桁数です。
# 精度の指定
x = 1/3
print(f"{x:.2f}") # 2桁に丸め
print(f"{x:.5f}") # 5桁に丸め
print(f"{12345.6789:.3g}") # 有効桁数3
0.33
0.33333
1.23e+04
符号(+ – space)の制御
+は正数にも+を付け、-は負数のみ符号、空白は正数にスペースを付けます。
p, n = 12, -12
print(f"{p:+d}, {n:+d}") # +12, -12
print(f"{p: d}, {n: d}") # 12, -12
print(f"{p:-d}, {n:-d}") # 12, -12 (デフォルト)
+12, -12
12, -12
12, -12
桁区切り(,)の指定
,で3桁ごとの区切りが入ります。
_でアンダースコア区切りも可能です。
# 桁区切り
m = 1234567890
print(f"{m:,}") # カンマ
print(f"{m:_}") # アンダースコア
1,234,567,890
1_234_567_890
- 関連記事:コピペで使える日付書式一覧
大文字小文字の指定
16進や指数表記は大文字/小文字を選べます。
x/X、e/E、g/Gなどです。
# 大文字/小文字指定
n = 48879
print(f"{n:x}") # 16進(小文字)
print(f"{n:X}") # 16進(大文字)
y = 12345.678
print(f"{y:e}") # 指数(小文字e)
print(f"{y:E}") # 指数(大文字E)
beef
BEEF
1.234568e+04
1.234568E+04
数値と日付のフォーマット
整数の基数(b o x X)
2進b、8進o、16進x/Xに対応します。
#で接頭辞(例:0x)を付けられます。
# 整数の基数
n = 255
print(f"{n:b}") # 2進
print(f"{n:o}") # 8進
print(f"{n:x}") # 16進(小)
print(f"{n:#x}") # 0x接頭辞あり
print(f"{n:#X}") # 0X接頭辞あり
11111111
377
ff
0xff
0XFF
小数と科学表記(f e E g)
固定小数点f、指数表記e/E、状況に応じて最適なg/Gがあります。
# 浮動小数の表記
x = 1234.56789
print(f"{x:.2f}") # 2桁固定
print(f"{x:.3e}") # 指数表記
print(f"{x:.6g}") # 有効桁数6
1234.57
1.235e+03
1234.57
パーセント(%)表示
%を使うと自動で100倍して%が付きます。
# パーセント表記
rate = 0.12345
print(f"{rate:.1%}") # 小数1桁の百分率
print(f"{rate:.2%}") # 小数2桁
12.3%
12.35%
- 関連記事:JSONを整形表示する方法
通貨風フォーマットのコツ
簡単にはf"¥{amount:,}"のように記述します。
負数や括弧表記などが必要なら規則を自作するかlocaleや外部ライブラリを使います。
# シンプルな通貨風表示
amounts = [1200, 9876543, -350]
for a in amounts:
sign = "-" if a < 0 else ""
print(f"{sign}¥{abs(a):,}")
¥1,200
¥9,876,543
-¥350
# localeを使った例(環境に依存します)
import locale
locale.setlocale(locale.LC_ALL, "ja_JP.UTF-8") # 環境にこのロケールが必要
n = 1234567.8
print(locale.currency(n, grouping=True)) # 例: '¥1,234,567.80'
¥1,234,568
日付時刻の書式(datetimeの%記法)
datetimeは__format__を実装しており、f"{dt:%Y-%m-%d %H:%M}"のようにstrftime互換の記法が使えます。
# 日付をf-stringで整形
from datetime import datetime
dt = datetime(2024, 5, 1, 14, 30, 5)
print(f"{dt:%Y-%m-%d %H:%M:%S}") # 2024-05-01 14:30:05
print(f"{dt:%Y年%m月%d日(%a) %H時%M分}") # ローカライズは環境に依存
2024-05-01 14:30:05
2024年05月01日(Wed) 14時30分
応用テクニックと注意点
条件式や関数呼び出しを埋め込む
{}の中には条件演算子も書けます。
ただし、複雑になりすぎる場合は事前に変数へ代入して可読性を保ちます。
# 三項演算子や関数呼び出し
score = 78
def rank(s):
return "A" if s >= 80 else "B" if s >= 65 else "C"
print(f"点数:{score} 評価:{rank(score)} "
f"合否:{'合格' if score >= 60 else '不合格'}")
点数:78 評価:B 合否:合格
dictやlistのキー/インデックス参照
辞書やリストへのアクセスも記述できます。
キーの引用符に注意します。
# dict, list 参照
user = {"name": "Alice", "age": 30}
nums = [10, 20, 30]
print(f"{user['name']}さんは{user['age']}歳です。最初の数は{nums[0]}です")
Aliceさんは30歳です。最初の数は10です
- 関連記事:辞書(dict)の基本的な使い方
ネストしたフォーマット指定
幅や精度を変数で動的に指定できます。
入れ子の{}でパラメータを渡すイメージです。
# 動的な幅や精度
pi = 3.1415926535
w, p = 8, 4
print(f"[{pi:{w}.{p}f}]") # 幅w, 小数p桁
n = 255
base = "X" # 'x' or 'X'
print(f"{n:#{base}}") # 0x/0X付きで16進
[ 3.1416]
0XFF
複数行f-stringとインデント
三重引用符で複数行を扱えます。
インデントを取り除きたい場合はtextwrap.dedentが便利です。
# 複数行のf-string
from textwrap import dedent
user = "Bob"
items = ["pen", "notebook"]
block = f"""
ユーザー: {user}
点数: {sum([40, 30])}
アイテム: {", ".join(items)}
"""
print(dedent(block).strip())
ユーザー: Bob
点数: 70
アイテム: pen, notebook
fr”…”の注意点(生文字列との併用)
fとrは併用可能です(fr"..."やrf"...")。
ただし生文字列はバックスラッシュを解釈しない一方、{}内の式は通常通り評価されます。
行末のバックスラッシュや一部のエスケープは注意が必要です。
# fr文字列の例
path = r"C:\Users\name"
pat = r"\d+"
print(fr"Path={path}, Regex={pat}, テスト={'\n'.join(['A','B'])!r}")
Path=C:\Users\name, Regex=\d+, テスト='A\nB'
パフォーマンスと可読性
一般にf-stringはformat()や%より高速です。
とはいえ、最優先は可読性で、過剰な入れ子や長大な式は避けるべきです。
必要に応じて事前に変数へ分解しましょう。
# 参考: 簡易ベンチマーク(結果は環境で変わります)
import timeit
print("f-string:", timeit.timeit("name='A'; n=1; f'{name} {n}'", number=1_000_000))
print("format():", timeit.timeit("name='A'; n=1; '{} {}'.format(name,n)", number=1_000_000))
print("%演算子 :", timeit.timeit("name='A'; n=1; '%s %d' % (name,n)", number=1_000_000))
f-string: 0.20
format(): 0.34
%演算子 : 0.26
セキュリティの注意(外部入力を式にしない)
外部入力を式として{}に評価する設計は危険です。
f-stringはソースコードに書かれた式を評価しますが、動的に式文字列を組み立ててeval()するのは避けましょう。
また、SQLやシェルへは必ずプレースホルダや安全なAPIを使います。
# 悪い例: 入力をevalで評価しない
# good例: SQLはパラメータ化する
import sqlite3
conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE t(id INT, name TEXT)")
name = "Alice'); DROP TABLE t; --"
cur.execute("INSERT INTO t VALUES (?, ?)", (1, name)) # 安全なプレースホルダ
conn.commit()
print("OK")
OK
バージョン互換性(Python 3.6+/=は3.8+)
f-string自体はPython 3.6+、デバッグ用の{expr=}は3.8+です。
古い環境を対象にする場合は注意してください。
| 機能 | 対応バージョン |
|---|---|
| f-string本体 | Python 3.6+ |
デバッグ表示{x=} | Python 3.8+ |
桁区切り_指定 | Python 3.6+ |
まとめ
f-stringは読みやすさ、書きやすさ、速度のバランスに優れた文字列整形手段です。
基本のf"…{式}…"で変数や式をシンプルに埋め込み、書式指定子で見た目を整え、数値や日付の定番パターンを覚えると多くの用途をカバーできます。
複雑なロジックは事前に変数へ分け、外部入力を式として評価しないという安全策を守れば、保守性と安全性の高いコードを書けます。
日常の出力からログ、レポート生成まで、まずはf-stringを標準の選択肢として活用してみてください。
- 関連記事:f-stringで変数名と値を同時出力
- 関連記事:f-string書式指定まとめ
