在Python里做字符串格式化,f-string和str.format是两套最常见方案。f-string从Python 3.6引入,用前缀f把变量或表达式直接写在花括号中;format方法则是字符串对象的内置函数,通过占位符和参数绑定完成替换。二者底层机制不同,适用场景也有区分。
一、基本语法与可读性对比
f-string的语法非常直观,开发者在写字符串时就能顺手把变量名填进花括号,不需要在字符串外再对应参数位置。这种写法让代码读起来像自然语言,尤其在拼接多个字段时优势明显。比如下面这段代码,姓名和年龄直接嵌入,一眼就能看懂输出结构。
name = "张三"
age = 28
# f-string直接嵌入变量
msg = f"用户{name}今年{age}岁"
print(msg)
str.format则采用占位符加参数方式,字符串本身是一个模板,真正的值通过format调用传入。当模板需要被多处复用,或者参数顺序需要动态调整时,这种写法更灵活。以下示例展示了用数字占位符和关键字占位符两种形式。
# 使用数字占位符,按顺序传参
tpl = "用户{0}今年{1}岁"
msg = tpl.format("李四", 30)
print(msg)
# 使用关键字占位符,参数可不按顺序
tpl2 = "用户{name}今年{age}岁"
msg2 = tpl2.format(age=25, name="王五")
print(msg2)
二、执行效率与底层机制
从性能角度看,f-string在字节码层面就被解释器优化。它在编译阶段就把花括号内的表达式转成对应的加载和格式化指令,运行时不需再解析占位符,也不产生额外的函数调用栈。因此循环里大量拼接字符串时,f-string通常比format快一截。
import timeit
# 测试f-string耗时
f_time = timeit.timeit('f"{x}+{y}"', setup='x=1; y=2', number=1000000)
# 测试format耗时
fmt_time = timeit.timeit('"{}+{}}".format(x, y)', setup='x=1; y=2', number=1000000)
print(f_time, fmt_time)
format方法每次调用都要先解析字符串里的占位符结构,再按规则匹配参数并转换类型,这中间涉及更多对象创建和方法调度。虽然在普通业务代码里这点差距不易感知,但在高频日志或批处理场景中积累起来就值得考虑。如果追求极致性能且模板固定,优先选f-string。
三、错误处理与调试能力
f-string在代码加载时就会检查花括号里的变量和表达式是否合法,引用了未定义名称会直接抛出NameError,问题暴露得很早。而format如果占位符写错或参数缺失,往往只会在运行时报错,甚至某些情况下把花括号原样保留,不容易第一时间发现。
# f-string引用不存在变量,启动即报错
# text = f"{not_exist}"; # 取消注释会抛NameError
# format漏传参数,运行才发现问题
t = "值:{0}"
# 下面这行会报IndexError
# t.format()
另外,f-string支持在表达式后加等号来同时输出变量名和值,对调试非常友好。format没有等价语法,只能手动拼字段名。这个细节在排查复杂拼接逻辑时很实用。
n = 5
# 调试时直接看变量名和值
print(f"{n=}") # 输出 n=5
四、适用场景总结
如果字符串模板是一次性拼接、逻辑简单且追求清晰,f-string是首选。它写起来快、读起来顺、跑起来也轻。如果模板需要作为独立配置存放、要在不同位置复用,或者参数顺序需要外部动态控制,format更合适。二者并非替代关系,而是互补工具。
| 对比维度 | f-string | str.format |
|---|---|---|
| 可读性 | 高,变量就近 | 中,需对照参数 |
| 性能 | 更优 | 稍弱 |
| 模板复用 | 弱 | 强 |
| 早暴露错误 | 是 | 部分 |
实际项目中可以根据上下文混用:固定文案用f-string,配置文件里的模板用format。这样既能保持代码简洁,又不失灵活性。
Pythonf-stringstr_format修改时间:2026-08-04 00:33:37