TL;DR:大部分人用 f-string 停在 f"{name}" 就不往下了,但好用的東西都在後面。冒號後面是格式設定(f"{price:.2f}"、千分位 :,、對齊 :>10);f"{x=}" 會直接印出 x=3,debug 時超省事(Python 3.8 起);Python 3.12 之後(PEP 701)連同引號巢狀、跨行、反斜線都解禁了,以前會 SyntaxError 的現在能寫。記住一句「冒號前是值,冒號後是長相」,大概就摸到八成了。

f"{name}" 這個寫法大家應該都會。要把變數塞進字串,前面加個 f、變數用 {} 框起來:

name = "Ada"
print(f"hello, {name}")
## hello, Ada

光這一步,就比以前的 "%s" % name"{}".format(name) 好讀太多,變數一多差距更明顯,你不用再去數後面括號裡的參數順序對不對。所以這篇不打算花篇幅比那兩個舊寫法,PEP 498 在 Python 3.6 就把這件事定下來了,能用 f-string 就用。

只是大多數人也就停在這裡。{} 裡面能放什麼、後面那串能寫什麼,才是 f-string 真正好用的地方。

冒號後面那串

{} 裡可以放的不只是變數名,是任何運算式。算式、呼叫方法、取索引都行:

print(f"{3 + 8}")              ## 11
print(f"{name.upper()}")       ## ADA

真正常被忽略的是冒號。{} 裡放一個冒號,前面是值,後面是它要長成什麼樣子:

price = 1/3
print(f"{price:.2f}")          ## 0.33   取小數兩位
print(f"{1234567:,}")          ## 1,234,567   加千分位逗號
print(f"{0.1827:.1%}")         ## 18.3%   轉百分比
print(f"{255:x}")              ## ff    轉十六進位
print(f"{5:b}")                ## 101   轉二進位

對齊也是同一個位置。> 靠右、< 靠左、^ 置中,後面接寬度:

print(f"{name:>10}|")          ## '       Ada|'
print(f"{name:^10}|")          ## '   Ada    |'

排東西成一欄的時候這個很順手,不用自己補空白。寬度還能是動態的——把另一個變數再用一層 {} 塞進去:

w = 8
print(f"{name:>{w}}|")         ## '     Ada|'

冒號後面那串叫 format spec,本身是一套小語法,上面只是最常用的幾個。記住「冒號前是值,冒號後是長相」,剩下要用再查就有。

變數後面加個 =,debug 省一半

這個我覺得是 f-string 最被低估的功能。你在 {} 裡的變數後面加一個 =,它會連名字帶值一起印出來:

x = 3
print(f"{x=}")                 ## x=3

聽起來沒什麼,但想想你平常 debug 怎麼印變數的。大概是 print("x =", x) 這樣打兩次 x,改名字還得改兩個地方。f"{x=}" 一次搞定,而且名字跟值保證對得起來。算式也行,它會把整串原樣印出來:

print(f"{x * 10 + 1=}")        ## x * 10 + 1=31

= 後面沒接東西時,值是用 repr() 印的,所以字串會自己帶引號,剛好分得出空字串跟一格空白。想要沒引號的 str() 版本,才要加 !s

name = "Ada"
print(f"{name=}")              ## name='Ada'   預設用 repr, 帶引號
print(f"{name=!s}")            ## name=Ada     !s 改用 str, 沒引號

這是 Python 3.8 加的。我自己現在 debug 幾乎只用這招,臨時想看某個值長怎樣,f"{那個值=}" 包一下就好。

3.12 之後鬆綁的那些限制

f-string 早期有些很煩的限制,到 Python 3.12(PEP 701)才一次解掉。最常踩到的是引號。3.12 以前,f-string 裡面不能再用同一種引號,所以這行會直接 SyntaxError

d = {"key": "val"}
f"{d["key"]}"                  ## 3.12 以前:SyntaxError

以前的解法是裡外換引號(f"{d['key']}"),或者乾脆先把值拉出來。3.12 之後就沒這回事了,同引號照寫照跑:

print(f"{d["key"]}")           ## val   (3.12+ 才行)

反斜線也是。以前運算式裡塞不進反斜線,連 '\n'.join(...) 這種常見寫法都得繞道:

xs = ["a", "b", "c"]
print(f"{'\n'.join(xs)}")      ## 3.12+ 才行,以前會炸
## a
## b
## c

還有跨行、{} 裡寫註解,現在也都合法了。要注意的就是版本——這些是 3.12 以後才有的,如果你的環境還卡在更舊的版本,上面那幾種寫法還是會炸,該繞還是得繞。

那有沒有不該用 f-string 的時候

有,幾個我會避開。

寫 log 的時候。logging.info(f"processing {user}") 會先把字串組好才丟進去,但如果這條 log 因為等級設定根本不會輸出,那串就白組了。logging.info("processing %s", user) 留給 logging 自己決定要不要組,省一點。差距平常摸不著,迴圈裡狂打 log 才現形。

還有把使用者輸入直接 f-string 拼進 SQL,這個是安全問題不是風格問題——f"SELECT ... WHERE id = {user_input}" 就是 SQL injection 的標準開法,這種一律走參數化查詢,別用 f-string。多語系(i18n / gettext)那種要把字串抽出去翻譯的場景也不適合,因為翻譯工具撈的是原始碼裡的靜態字串,f-string 沒留下那個能被抽出去對照的固定字面值。

這幾個之外,日常要把值湊成一段字串,f-string 大概都是最順的選擇。

真要記,記冒號那條,debug 時 f"{值=}" 練成反射,其他查得到。f-string 學一次能用很久,多花十分鐘往 {} 後面多看一眼,划算。

想再翻翻 Python 其他讓程式變短的小東西,可以順手看看 Python 列表推導式:一行取代 for 迴圈


本文範例都在 Python 3.14.3 上實際跑過。想看源頭的話:PEP 498 — Literal String Interpolation(f-string 的起點)、PEP 701 — Syntactic formalization of f-strings(3.12 的鬆綁)、Format Specification Mini-Language(冒號後面那套完整語法)。