Python基础指南之字符串格式化百分号%的用法详解
作者:星河耀银海
本文详细介绍了Python最古老的格式化方式——百分号%的用法,包括基本语法、占位符、精度控制及实战示例;并对比了其与str.format()和f-string的差异,强调了百分号格式化在老项目维护及简单调试中的应用价值
一、开篇:最古老的Python格式化方式
Python有三种字符串格式化方式,按出现的时间顺序:
- 百分号
%:Python诞生时就有的,最古老 str.format():Python 2.6引入,功能更强大- f-string(
f'...'):Python 3.6引入,最现代、最推荐
今天我们先讲第一种——百分号格式化。虽然它是"老古董",但很多老项目中仍然大量使用,而且某些场景下它写起来特别简洁。了解它能帮你读懂和维护存量代码,也能在一些简单场景中快速完成任务。
二、百分号格式化的基本语法
2.1 语法形式
# 基本语法 result = "格式化字符串" % (值1, 值2, ...) # 最简单的例子 name = '小明' age = 25 text = '我叫%s,今年%d岁' % (name, age) print(text) # 我叫小明,今年25岁
语法结构:
%s、%d这些是占位符,标记了"这里要插入一个值"- 字符串末尾的
%是运算符,连接模板和实际值 (name, age)是值的元组,按顺序填入占位符
2.2 占位符速查表
| 占位符 | 含义 | 示例 |
|---|---|---|
%s | 字符串(自动调用str()) | '%s' % 'hello' → 'hello' |
%d | 十进制整数 | '%d' % 42 → '42' |
%i | 整数(同%d) | '%i' % 42 → '42' |
%f | 浮点数 | '%f' % 3.14 → '3.140000' |
%e | 科学计数法(小写e) | '%e' % 1000 → '1.000000e+03' |
%E | 科学计数法(大写E) | '%E' % 1000 → '1.000000E+03' |
%x | 十六进制(小写) | '%x' % 255 → 'ff' |
%X | 十六进制(大写) | '%X' % 255 → 'FF' |
%o | 八进制 | '%o' % 8 → '10' |
%c | 字符(接受整数或单个字符) | '%c' % 65 → 'A' |
%r | 字符串repr()表示 | '%r' % 'hello' → "'hello'" |
%% | 百分号本身 | '%%' → '%' |
2.3 基本使用示例
# %s——万能占位符(适合快速输出)
name = '小明'
score = 95.5
items = [1, 2, 3]
print('姓名:%s' % name) # 姓名:小明
print('分数:%s' % score) # 分数:95.5(自动转字符串)
print('列表:%s' % items) # 列表:[1, 2, 3]
# %d——整数(不接受浮点数)
print('年龄:%d' % 25) # 年龄:25
# print('年龄:%d' % 25.5) # TypeError!%d不能接受浮点数
# %f——浮点数
print('π ≈ %f' % 3.14159) # π ≈ 3.141590(默认6位小数)
# 多个占位符
name = '小明'
age = 25
height = 1.75
print('%s,%d岁,身高%.2f米' % (name, age, height))
# 小明,25岁,身高1.75米
注意:当只有一个值时,括号可以省略;但如果是元组,需要括号:
print('%s' % 'hello') # 单个值,可以不写括号
# print('%s' % ('hello',)) # 也可以写括号
# print('%s %s' % 'a', 'b') # 错误!多个值不用括号会报错
print('%s %s' % ('a', 'b')) # 正确
三、格式化精度控制
3.1 控制浮点数的小数位数
pi = 3.141592653589793
print('%.2f' % pi) # 3.14(保留2位小数)
print('%.4f' % pi) # 3.1416(保留4位小数,四舍五入)
print('%.10f' % pi) # 3.1415926536
print('%f' % pi) # 3.141593(默认6位)
# 整数也可以用小数控制(但通常不需要)
print('%.2f' % 42) # 42.00
3.2 控制宽度和对齐
# 固定宽度(右对齐,默认)
print('%10s' % 'hello') # ' hello'
print('%10d' % 42) # ' 42'
print('%10.2f' % 3.14) # ' 3.14'
# 左对齐(负号)
print('%-10s' % 'hello') # 'hello '
print('%-10d' % 42) # '42 '
# 补零(数字前面补0)
print('%010d' % 42) # '0000000042'
print('%010.2f' % 3.14) # '0000003.14'
# 居中对齐?百分号不支持,需要format()或f-string
3.3 格式化实战
# 打印对齐的表格
students = [
('小明', 20, 85.5),
('小红', 21, 92.0),
('小刚', 19, 78.5),
]
print('%-8s %-6s %-8s' % ('姓名', '年龄', '成绩'))
print('-' * 24)
for name, age, score in students:
print('%-8s %-6d %-8.1f' % (name, age, score))
# 输出:
# 姓名 年龄 成绩
# ------------------------
# 小明 20 85.5
# 小红 21 92.0
# 小刚 19 78.5
四、%s 和 %r 的区别
# %s:调用str()——给人看的
# %r:调用repr()——给调试看的
x = 'hello'
print('%s' % x) # hello
print('%r' % x) # 'hello'(带引号)
# 对于字符串,区别很明显
name = '小明'
print('名字是%s' % name) # 名字是小明
print('名字是%r' % name) # 名字是'小明'
# 对于数字,区别不大
print('%s' % 42) # 42
print('%r' % 42) # 42
# repr在调试中很有用
value = ' hello \n'
print('str: [%s]' % value) # str: [ hello ]
print('repr: [%r]' % value) # repr: [' hello \n'](看到换行符和空格)
%s 适合最终输出(给用户看),%r 适合调试日志(给开发者看)。
五、百分号格式化的高级用法
5.1 用字典传值
# 当格式化字符串很长、需要插入的值很多时,用字典可以避免一一对应的混乱
person = {
'name': '小明',
'age': 25,
'city': '北京',
'job': '软件工程师'
}
template = '我叫%(name)s,今年%(age)d岁,来自%(city)s,职业是%(job)s。'
print(template % person)
# 我叫小明,今年25岁,来自北京,职业是软件工程师。
# 用字典的优势:可以重复使用同一个值
template = '%(name)s的年龄是%(age)d,%(name)s住在%(city)s。'
print(template % person)
# 小明的年龄是25,小明住在北京。
5.2 动态宽度(用*传宽度)
# 宽度可以动态指定
width = 10
precision = 3
print('%*.*f' % (width, precision, 3.14159))
# ' 3.142'(宽度10,保留3位小数)
# 这在生成动态格式的报告中很有用
def print_table(data, col_widths):
for row in data:
format_str = ''
for width in col_widths:
format_str += '%-*s '
# 构建: '%-*s %-*s %-*s '
print(format_str % tuple(
item for pair in zip(col_widths, row) for item in pair
))
data = [('小明', '北京', '工程师'), ('小红', '上海', '设计师')]
print_table(data, [8, 6, 8])
六、常见错误和注意事项
6.1 占位符和值的数量不匹配
# ❌ 占位符比值多
# print('%s %s %s' % ('a', 'b')) # TypeError: not enough arguments
# ❌ 值比占位符多
# print('%s' % ('a', 'b')) # TypeError: not all arguments converted
# ✅ 占位符和值数量对应
print('%s %s' % ('a', 'b')) # a b
# 只有一个值时不需要元组(但如果值本身是元组要注意)
print('%s' % ('hello',)) # hello
print('%s' % (('a', 'b'),)) # ('a', 'b') —— 整个元组被当作一个值
6.2 占位符和值的类型不匹配
# %d 不接受浮点数
# print('分数:%d' % 95.5) # TypeError
# 解决方法:先转换
print('分数:%d' % int(95.5)) # 分数:95
# 或者直接用%s
print('分数:%s' % 95.5) # 分数:95.5
# %f 不接受字符串
# print('价格:%f' % '十元') # TypeError
6.3 忘记转义百分号
# 如果你想在格式化字符串中显示百分号本身
# ❌ 错误写法
# print('完成度:%d%' % 80) # ValueError
# ✅ 用 %% 转义
print('完成度:%d%%' % 80) # 完成度:80%
# 多个百分号
print('增长率为%.2f%%' % 15.678) # 增长率为15.68%
七、百分号格式化 vs format() vs f-string
name = '小明'
age = 25
score = 95.5
# 三种方式对比
# 1. 百分号——古老简洁
s1 = '我叫%s,今年%d岁,成绩%.1f分' % (name, age, score)
# 2. format()——功能强大
s2 = '我叫{},今年{}岁,成绩{:.1f}分'.format(name, age, score)
# 3. f-string——最现代最推荐
s3 = f'我叫{name},今年{age}岁,成绩{score:.1f}分'
print(s1) # 三种方式输出一样
print(s2)
print(s3)
| 特性 | % 格式化 | str.format() | f-string |
|---|---|---|---|
| Python版本 | 所有版本 | 2.6+ | 3.6+ |
| 可读性 | 一般 | 较好 | 最好 |
| 表达式支持 | 不支持 | 支持 | 支持 |
| 字典引用 | 支持 | 支持 | 支持 |
| 性能 | 一般 | 一般 | 最快 |
| 重复使用模板 | 支持 | 支持 | 需重新构建 |
选择建议:
- 新代码:优先使用 f-string
- 需要复用模板:使用
str.format() - 维护老代码:了解百分号语法,不要强行改
- 简单快速调试:百分号一行搞定
'%s=%r' % (name, value)
八、何时仍然使用百分号
# 场景一:日志模块——logging推荐使用百分号
import logging
logging.basicConfig(level=logging.INFO)
# logging内部使用百分号格式化
# 这样写可以让日志系统延迟执行字符串格式化(性能优化)
name = '小明'
logging.info('用户 %s 登录了系统', name)
# 注意:这里是逗号分隔,不是%运算符
# 场景二:维护使用百分号的老代码
# 如果整个项目已经用了百分号风格,保持一致
# 不要在新旧风格间跳来跳去
# 场景三:简单的调试输出
print('x=%d, y=%d, sum=%d' % (x, y, x + y))
# 虽然 f'{x=} {y=}' 更好,但老习惯改不掉
九、实战:用百分号格式化生成报告
def generate_sales_report(month, data):
"""生成销售报告"""
report = []
report.append('=' * 50)
report.append('%s月销售报告' % month)
report.append('=' * 50)
report.append('')
report.append('%-20s %-10s %-10s' % ('商品名称', '销量', '销售额'))
total_quantity = 0
total_revenue = 0.0
for item_name, quantity, price in data:
revenue = quantity * price
report.append('%-20s %-10d ¥%-9.2f' % (item_name, quantity, revenue))
total_quantity += quantity
total_revenue += revenue
report.append('-' * 50)
report.append('%-20s %-10d ¥%-9.2f' % ('合计', total_quantity, total_revenue))
report.append('=' * 50)
return '\n'.join(report)
data = [
('Python编程书', 150, 59.9),
('机械键盘', 80, 299.0),
('显示器支架', 45, 159.0),
('USB数据线', 300, 19.9),
]
print(generate_sales_report('5', data))
十、本篇小结
百分号格式化是Python最古老的字符串格式化方式:
- 基本语法:
"模板%s %d" % (值1, 值2) - 常用占位符:
%s(字符串)、%d(整数)、%f(浮点数) - 精度控制:
%.2f(保留2位小数)、%10s(宽度10右对齐)、%-10s(左对齐) - 字典传值:
%(name)s按名称引用,适合长模板 - 转义百分号:用
%%输出一个%
虽然在新项目中推荐使用 f-string,但百分号格式化在日志模块、老项目维护、简单调试中仍然有其位置。下一篇我们进入 str.format()——功能更强大的格式化方式。
以上就是Python基础指南之字符串格式化百分号%的用法详解的详细内容,更多关于Python字符串格式化的资料请关注脚本之家其它相关文章!
