Python 3.6 引入的 f-string(Formatted String Literals)把变量和表达式直接写进字符串:前缀加 f 或 F,花括号 {} 里放要替换的内容。和 %-formatting、str.format() 相比,它省掉了格式符映射和参数传递,解释器在编译阶段就解析花括号内的表达式,因此执行效率更高,也更容易在拼接字符串时保持可读性。下面按“基础嵌入—格式控制—调试—错误排查—选型”的顺序,把常用写法和容易踩的坑集中梳理一遍。
一、变量、表达式与函数调用
f-string 的花括号内可以放任意合法 Python 表达式,包括算术运算、字符串方法、逻辑判断和函数调用。不需要提前把结果算出来再拼接,代码更紧凑:
- name = "Alice"
- age = 28
- print(f"姓名:{name},年龄:{age}") # 姓名:Alice,年龄:28
- print(f"明年年龄:{age + 1}") # 明年年龄:29
- print(f"姓名大写:{name.upper()}") # 姓名大写:ALICE
- print(F"姓名长度:{len(name)}") # 姓名长度:5
- a, b = 10, 3
- print(f"{a} + {b} = {a + b}") # 10 + 3 = 13
- print(f"{a} ÷ {b} = {a / b:.2f}") # 10 ÷ 3 = 3.33
- text = "python"
- print(f"首字母大写:{text.capitalize()}") # 首字母大写:Python
- print(f"是否为空:{len(text) == 0}") # 是否为空:False
- def get_full_name(first_name, last_name):
- return f"{first_name} {last_name}"
- print(f"全名:{get_full_name('John', 'Doe')}") # 全名:John Doe
复制代码
这里要注意,花括号内写的是表达式而不是任意语句,表达式本身必须语法完整,函数调用要带括号,运算符不能悬空,否则会在编译阶段直接报 SyntaxError。
二、格式说明符:精度、宽度、对齐与进制
在花括号内用冒号引出格式说明符,写法和 str.format() 保持一致。常用的是“宽度.精度+类型字符”,例如 .2f 表示保留两位小数,10.4f 表示总宽度 10、保留四位小数。
浮点数场景:
- pi = 3.1415926535
- print(f"圆周率(保留2位):{pi:.2f}") # 3.14
- print(f"圆周率(宽度10,保留4位):{pi:10.4f}") # 右对齐,前面补空格,3.1416
- print(f"科学计数法:{pi:.2e}") # 3.14e+00
复制代码
整数场景主要用宽度、对齐和补零。d 表示十进制,x 和 o 分别输出十六进制和八进制;- 表示左对齐,0 表示左侧补零:
- num = 123
- print(f"右对齐:{num:10d}") # 宽度10,默认右对齐
- print(f"左对齐:{num:-10d}") # 宽度10,左对齐,右侧补空格
- print(f"补零:{num:010d}") # 0000000123
- print(f"十六进制(小写):{num:x}") # 7b
- print(f"八进制:{num:o}") # 173
复制代码
百分比用 % 类型符,数值会自动乘以 100 并追加百分号。默认保留 6 位小数,需要更短的结果时用 .2% 这样的精度限定:
- rate = 0.789
- print(f"百分比:{rate:%}") # 78.900000%
- print(f"百分比(保留2位):{rate:.2%}") # 78.90%
复制代码
三、日期时间与嵌套格式化
datetime 对象可以直接用日期格式符输出,不必先 strftime 再拼接:
- from datetime import datetime
- now = datetime.now()
- print(f"当前时间:{now:%Y-%m-%d %H:%M:%S}")
- print(f"今日日期:{now:%Y年%m月%d日}")
- print(f"今天是:{now:%A}") # 英文星期名
- print(f"今天是:{now:%w}") # 数字,0 表示周日
复制代码
当精度本身来自变量时,可以在格式说明符里再嵌一层花括号。下面 precision 为 2,最终按两位小数输出:
- precision = 2
- pi = 3.1415926535
- print(f"圆周率(保留{precision}位):{pi:.{precision}f}") # 3.14
复制代码
嵌套也可以用于条件表达式,但可读性会明显下降。层级较深时,建议先在普通变量里算出结果,再放进 f-string:
- score = 85
- print(f"成绩评级:{f'优秀({score}分)' if score >= 90 else f'良好({score}分)' if score >= 80 else '合格'}")
复制代码
四、调试写法:{变量=}
排查问题时,经常需要打印“变量名=值”。在花括号内变量后面加等号,可以自动输出变量名和值,还能继续接格式说明符:
- x = 10
- y = 20
- print(f"{x=}, {y=}, {x+y=}") # x=10, y=20, x+y=30
- print(f"{x=:05d}, {y=:.2f}") # x=00010, y=20.00
复制代码
这种写法适合临时调试,正式日志中仍建议使用 logging 并保留结构化字段,避免输出格式随变量名变化而失控。
五、常见错误与排查思路
1. 花括号内语法不完整
表达式缺少运算符右侧、括号不配对,都会让解释器在解析 f-string 时抛出 SyntaxError。变量未定义则是在运行阶段抛 NameError。遇到报错先检查花括号内是否是一个完整表达式,再确认变量作用域。
- # print(f"结果:{x + y *}") # SyntaxError
- # print(f"未定义变量:{undefined_var}") # NameError
复制代码
2. 引号冲突
外部字符串和内部表达式使用同一种引号时,容易提前结束字符串。处理方式是内外引号错开,或在内部使用转义符:
- # print(f"姓名:{name's}") # SyntaxError
- print(f"姓名:{name}'s") # 姓名:Alice's
- print(f'姓名:{name}\'s') # 姓名:Alice's
复制代码
3. 浮点数精度误差
f-string 只改变显示格式,不改变浮点数的二进制存储结果。0.1 + 0.2 的真实结果仍是 0.30000000000000004,.1f 只是把显示结果四舍五入成 0.3。金融等高精度场景不要依赖格式化来“修正”数值,应改用 decimal 模块参与计算。
- a = 0.1
- b = 0.2
- print(f"0.1 + 0.2 = {a + b}") # 0.30000000000000004
- print(f"0.1 + 0.2 = {a + b:.1f}") # 显示为 0.3
复制代码
4. 版本兼容性
f-string 从 Python 3.6 开始支持。如果项目还要运行在 Python 3.5 及以下环境,只能回退到 str.format() 或 %-formatting。维护旧代码时,先确认目标解释器版本,再决定是否批量替换格式化写法。
六、三种格式化方式的选型
%-formatting 兼容所有 Python 版本,但格式符和参数需要按位置对应,参数一多就容易错位;str.format() 支持位置参数和关键字参数,从 Python 2.6、3.0 起可用,适合需要复用参数或动态拼接模板的场景;f-string 语法最简、执行效率最高,支持表达式、嵌套和格式说明符,但要求 Python 3.6+。
实际项目中可以这样取舍:新代码优先用 f-string;需要兼容旧解释器时用 str.format();维护历史代码或第三方模板时保留原有的 %-formatting。掌握花括号内嵌表达式、冒号后的格式说明符,以及引号冲突和浮点误差这两个高频问题,基本就能覆盖日常字符串格式化的绝大多数需求。 |