字符串格式化:把值变成好看的文字
以打印一张设备状态报表为场景,一次学会 f-string 格式说明符:小数位、千分位、百分比、对齐补零与调试专用的 {x=};顺带说清 str.format 与 % 风格如今还活在哪里。
前置知识
读过 基本数据类型,知道 f-string 是「引号前加 f,大括号里放变量」;用过 变量与常量 里的赋值。
场景:一行报表逼出的格式需求
你在给 ESP32 玩具设备做巡检脚本(作者项目 FoloToy-calendar 就要干这个),从接口拿到原始数据,想打印一行人能读的状态:
device = {"name": "bedroom-01", "uptime_s": 987654, "battery": 0.873, "fw": "2.3.1"}
print(f"{device['name']} 运行 {device['uptime_s']}s 电量 {device['battery']} 固件 {device['fw']}")bedroom-01 运行 987654s 电量 0.873 固件 2.3.1三个毛病:电量是 0.873 想显示 87.3%;987654 秒数没有千分位,数位要靠手数;名字一长整行就错位,没法竖着扫。这些都不是计算问题,是格式化问题——f-string 冒号后面的「格式说明符」就是为此存在的。
动手做:五分钟把报表改像样
device = {"name": "bedroom-01", "uptime_s": 987654, "battery": 0.873, "fw": "2.3.1"}
name = f"{device['name']:<12}" # 左对齐,占 12 格
up = f"{device['uptime_s']:,}" # 千分位
bat = f"{device['battery']:.1%}" # 乘 100 加 %,保留 1 位小数
print(f"{name} 运行 {up:>9}s 电量 {bat:>6} 固件 {device['fw']}")bedroom-01 运行 987,654s 电量 87.3% 固件 2.3.1规则一条就能推导所有写法:{值:填充 对齐 宽度, 分组. 精度 类型}。不背全表,先记最常用的五招:
| 写法 | 含义 | 示例 | 输出 |
|---|---|---|---|
{x:.2f} | 保留 2 位小数 | f"{3.14159:.2f}" | 3.14 |
{x:,} | 千分位逗号 | f"{987654:,}" | 987,654 |
{x:.1%} | 百分比(自动乘 100) | f"{0.873:.1%}" | 87.3% |
{x:>8} | 右对齐占 8 格 | f"{7:>8}" | ' 7' |
{x:04d} | 补零到 4 位 | f"{42:04d}" | 0042 |
对齐符号三个方向:< 左、> 右、^ 居中;数字默认右对齐、字符串默认左对齐,所以给数字写 :>9 往往是显式声明而非必须。
为什么是这样
冒号后那串字符不是 f-string 发明的语法,而是标准库的格式说明迷你语言(Format Specification Mini-Language),str.format() 与 f-string 共用同一套。三个方法的关系按 2026 年的实务排序:
- f-string(首选):Python 3.6 引入,3.12 起(PEP 701)连引号嵌套、换行表达式都放开了,没有理由再用别的;
str.format():模板字符串存成变量、多处复用时仍顺手:tpl = "{name} 得 {score}",之后tpl.format(name="小明", score=85);%风格:新代码不写,但日志里还大量存在且是推荐写法——logger.debug("处理 %s", data)的延迟格式化能省性能(原因见 日志),读老代码也躲不开。
坑点实录
坑一:中文对不齐。宽度按「字符个数」算,中文一个字也只占 1 格,但显示宽度是 2,混排报表照样歪。标准库没有内置解法,要么全英文排版,要么用第三方 wcwidth 算显示宽度再手动补格。
坑二:{x:.2f} 不能喂给字符串。f"{'abc':.2f}" 抛 ValueError: Unknown format code 'f' for object of type 'str'——报错里的 'f' 就是类型码,读到这句先检查值的类型。
坑三:说明符内部的顺序写反。迷你语言各段有固定次序:对齐、宽度、千分位、精度、类型,即 :>10,.2f 这种形状。写成 f"{987654:>,10}" 会报 ValueError——千分位 , 必须排在宽度之后:f"{987654:>10,}" 输出 ' 987,654'。
坑四:调试时懒得拆 print。3.8 起有个专用语法,等号会同时打印变量名和值:
hp = 86.54321
print(f"{hp=}") # hp=86.54321
print(f"{hp = :.1f}") # hp = 86.5(等号两侧空格会保留,仍可用格式符)hp=86.54321
hp = 86.5自我检查
- 不查表能写出:两位小数、千分位、百分比、右对齐占 10 格;
- 能说出
%风格在什么场景仍是推荐(日志延迟格式化); - 知道中文对不齐的原因(宽度按字符数而非显示宽度);
- 能用
{x=}一次打印变量名与值。
小练习
- 预测题:
f"{0.07:.0%}"输出什么?先写答案再运行(注意四舍五入)。 - 修改题:把本文报表扩一列
rssi(信号强度,整数,负数如-67),要求右对齐占 6 格,负数自然带符号。 - 实战题:写函数
money(cents: int) -> str,输入分、输出元,如money(12345)得"123.45";补一条断言assert money(5) == "0.05",体会补零与精度怎么配合。
下一步
- 报表要按列对齐输出到文件,见 文件 IO 与上下文管理器;
- 文字不是「排好看」而是「拆出结构」时,进入 正则表达式;
- f-string 在 3.12 里彻底放开限制(嵌套引号、多行、注释)的细节,见 版本新特性时间线。