Python print怎么实现格式化输出(f-string与format)

陆景行
陆景行
发布时间:2026-10-24 | 6人浏览过
原创

在 Python 中,单纯使用 print(a, b, c) 只能通过空格将多个变量做简单的顺序连接,一旦面对保留特定小数位数、字符左右对齐、指定列宽补齐或嵌入动态报表等场景,这种方式就难以满足排版需求。实现精确、美观的控制台输出,核心在于使用 Python 提供的字符串格式化机制生成目标字符串,再传递给 print() 函数打印。目前 Python 生态中最通用、最高效的两种实现方式分别是 Python 3.6 引入的 f-string(格式化字符串字面值) 与 Python 2.6 引入的 str.format() 方法。本文将系统拆解这两种方式的具体写法、参数规则、格式规范微语言,以及在实际开发中的选型考量。

Python print怎么实现格式化输出(f-string与format)
图 1:Python 格式化输出方式的技术演进与核心机制对比

一、使用 f-string 实现格式化输出

f-string 的全称为 Formatted String Literals。它的使用方式是在字符串开头的引号前加上字母 f 或 F。此时字符串内部的花括号 {} 不再作为纯文本输出,而是被解析为 Python 表达式容器,其中的变量或表达式会在运行时求值并自动转换为字符串。

1. 基础变量嵌入与表达式计算

在花括号中,不仅可以直接写入变量名称,还可以包含算术运算、字符串方法调用以及内建函数:

name = "Alice"
score = 88.5
bonus = 5

# 基础变量插值
print(f"学员姓名: {name}")

# 花括号内支持直接执行数学运算与方法调用
print(f"最终总分: {score + bonus}, 姓名大写: {name.upper()}")
控制台输出结果
学员姓名: Alice
最终总分: 93.5, 姓名大写: ALICE

2. Python 3.8+ 便捷调试语法

在日常打印日志或排查变量时,我们往往需要同时输出“变量名”和“变量当前值”。在 Python 3.8 及以上版本中,可以在花括号表达式末尾直接添加等号 =,解释器会自动输出表达式字面量及其结果:

width = 120
height = 80

# 使用 = 号快速打印变量名及求值结果
print(f"{width=}, {height=}, {width * height=}")
控制台输出结果
width=120, height=80, width * height=9600

二、使用 str.format() 方法实现格式化输出

str.format() 是字符串对象的一个内建方法。它通过在字符串模板中预置 {} 占位符,然后调用 .format() 传入对应的数据进行填充。与 f-string 最大的形态差异在于:模板字符串与待填充的数据在语法上是分离的。

Python print怎么实现格式化输出(f-string与format)
图 2:f-string 与 str.format() 的执行流程与数据绑定步骤

1. 位置参数与索引复用

如果不填写占位符内的索引,format() 会按顺序依次填入实参;如果填入明确的索引序号,不仅可以打破传参顺序,还能在同一个模板中多次重复使用同一个参数:

# 默认顺序填入
print("项目: {}, 状态: {}".format("数据清洗", "已完成"))

# 明确索引序号,可随意调换显示顺序并支持多次复用
print("版本 {0} 发布成功!请所有使用 {0} 的用户查阅变更说明。".format("v2.4.0"))
控制台输出结果
项目: 数据清洗, 状态: 已完成
版本 v2.4.0 发布成功!请所有使用 v2.4.0 的用户查阅变更说明。

2. 关键字参数与容器解包

当格式化项较多时,使用数字索引容易发生记忆偏差。通过关键字参数指定名称,或者结合解包操作符 ** 传入字典,能大幅提升模板的可读性:

# 使用关键字参数
print("主机: {host}, 端口: {port}".format(host="127.0.0.1", port=8080))

# 字典解包传参
server_info = {"host": "192.168.1.100", "port": 3306, "status": "active"}
print("连接数据库 {host}:{port} [状态: {status}]".format(**server_info))
控制台输出结果
主机: 127.0.0.1, 端口: 8080
连接数据库 192.168.1.100:3306 [状态: active]

三、格式规范微语言:对齐、补位与数值格式化

无论是 f-string 还是 str.format(),在冒号 : 后面都可以紧跟一套统一的格式规范微语言(Format Specification Mini-Language)。这套规范是控制输出样式的核心工具。

Python print怎么实现格式化输出(f-string与format)
图 3:格式规范微语言的主要语法组成及效果示例

1. 宽度与对齐控制示例

title = "Python教程"

# 左对齐、居中对齐、右对齐,设定总宽度为 16
print(f"|{title:<16}|")
print(f"|{title:^16}|")
print(f"|{title:>16}|")

# 结合指定字符进行空位填充(例如使用减号填充)
print(f"|{title:-^16}|")
控制台输出结果
|Python教程 |
| Python教程 |
| Python教程|
|----Python教程----|

2. 数字精度、千分位与百分比格式化

amount = 1284560.785
ratio = 0.8524

# 包含千分位逗号且保留 2 位小数
print(f"交易金额: {amount:,.2f}")

# 百分比格式化(自动乘以 100 并保留 1 位小数)
print(f"达成比率: {ratio:.1%}")

# 进制转换:十进制转为二进制与十六进制
number = 255
print(f"二进制: {number:#b}, 十六进制: {number:#x}")
控制台输出结果
交易金额: 1,284,560.79
达成比率: 85.2%
二进制: 0b11111111, 十六进制: 0xff
提示:如果需要在字符串中打印字面量花括号 { 或 },可以通过双写花括号实现转义。例如 f"{{code: {200}}}" 输出结果为 {code: 200}。

四、f-string 与 str.format() 的关键差异对比

为了让读者在实际编写代码时做出清晰的选择,我们需要在相同条件下审视两种方案的核心差异:

对比维度 f-string(格式化字符串字面值) str.format() 方法
求值时机与机制 在代码运行到该行时即时求值,被编译器直接优化为底层专用指令(如 BUILD_STRING / FORMAT_VALUE)。 属于常规的方法调用过程,先在内存中产生普通字符串模板,调用方法时再将参数逐个推入栈并解析替换。
动态模板支持 不支持外部动态加载。表达式必须在编写代码时静态确定,无法从 .json、数据库或国际化文案文件中动态读取 f-string 模板并渲染。 原生支持动态模板。模板字符串可以保存在任意外部配置文件或变量中,在运行时随时传入参数完成渲染。
代码可读性 变量名直接置于占位符中,阅读时视线集中,不需要频繁在末尾参数表与模板之间来回比对。 当参数较多或格式较长时,尾部 .format(...) 的参数列表与前半部分的 {} 产生物理距离,易产生对应错位。
执行性能 性能极高。由于省去了函数调用的开销和运行时占位符匹配解析,通常比 format() 快 1.5 到 3 倍。 中等性能。存在函数调用以及每次调用时的占位符遍历解析成本。
安全性考量 安全性高,表达式由代码作者静态写明,外部不可注入代码。 若接收不受信任的外部用户输入作为模板,可能通过 {user.__class__.__init__} 等属性暴露底层对象结构。
Python print怎么实现格式化输出(f-string与format)
图 4:f-string 与 str.format() 场景选型决策指南

五、实战示例:生成结构化对齐报表

为了展示格式化输出在实际项目中的综合应用,以下代码构建了一个控制台商品销售清单。通过合理组合对齐方式(文本靠左、数字靠右)、列宽约束以及浮点数千分位截断,实现整齐划一的排版:

# 销售数据列表
items = [
    {"name": "机械键盘", "category": "外设", "qty": 2, "price": 499.0},
    {"name": "超高清显示器", "category": "数码", "qty": 1, "price": 2899.5},
    {"name": "无线人体工学鼠标", "category": "外设", "qty": 3, "price": 188.0},
]

# 1. 打印表头:定义固定列宽与对齐方向
print(f"{'品名':<14}{'分类':<8}{'数量':>6}{'单价(元)':>12}{'小计(元)':>14}")
print("-" * 56)

total_amount = 0.0

# 2. 遍历数据行输出
for item in items:
    subtotal = item["qty"] * item["price"]
    total_amount += subtotal
    print(
        f"{item['name']:<14}"
        f"{item['category']:<8}"
        f"{item['qty']:>6d}"
        f"{item['price']:>12,.2f}"
        f"{subtotal:>14,.2f}"
    )

print("-" * 56)
# 3. 打印汇总行
print(f"{'总计金额:':<40}{total_amount:>14,.2f}")
控制台输出结果
品名 分类 数量 单价(元) 小计(元)
--------------------------------------------------------
机械键盘 外设 2 499.00 998.00
超高清显示器 数码 1 2,899.50 2,899.50
无线人体工学鼠标 外设 3 188.00 564.00
--------------------------------------------------------
总计金额: 4,461.50

六、常见问题与注意事项

1. 引号嵌套冲突

在 f-string 中访问字典键时,字典键的引号必须与外部 f-string 的引号不同。例如,如果外层使用了双引号 f"{...}",则花括号内部字典索引必须使用单引号 item['key']。在 Python 3.12 之前,若内外层引号完全相同会导致语法解析错误(SyntaxError)。

2. 避免在不受信任的外部输入中使用 format()

str.format() 拥有访问对象内部属性的能力。如果直接将前端用户输入的字符串作为模板并调用 format(),攻击者可能会通过构造形如 "{user.__class__.__init__.__globals__}" 的占位符探测运行环境中的全局变量。对于外部输入的模板,应使用白名单过滤或专用的模板解析器。

3. 多行长字符串的换行拼接

如果格式化语句较长,建议利用 Python 的括号隐式行连接特性,将多个带有 f 前缀的短字符串分行放置,避免单行代码过长破坏代码可读性:

# 推荐的多行拼接写法
message = (
    f"用户ID: {user_id}\n"
    f"登录IP: {client_ip}\n"
    f"认证耗时: {duration:.3f}s"
)
print(message)

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表