对于学过其他编程语言(尤其是 C/C++)的 Python 新手来说,心中难免会有一个疑问:Python 中有 printf 吗?
如果你回答“有 print,但没有 printf”,这只算答对了一半,甚至可以说是答错了。
那么,Python 中究竟有没有 printf 呢?O(∩_∩)O哈哈~的确没有,但 printf 的功能 Python 却有。为此,字符串类重载了取模运算符“%”,以实现字符串的格式化。
1
工作原理
“%”代表格式符(也叫占位符),
表示格式化操作,其语法规则
如下:
%[(name)][flags][width].[precision]typecode
- (name):可选,用于选择指定的 key。
- flags:可选,表示辅助符号(例如:+、0 等)。
- width:可选,占有宽度。
- .precision:可选,小数点后保留的位数。
- typecode:必选,类型码(例如:%d 对应的就是 d)。
为了明确以上概念,用一张图来介绍下它的工作原理:
在这个图中,格式符“%”的左侧(绿色虚线部分)是所谓的格式字符串,其右侧(橙色虚线部分)是一个包含实际内容的元组,它会被插入到格式字符串中。
格式字符串包含占位符,在这里有两个 - “%10s”和“%8.2f”:
- 第一个占位符“%10s”表示字符串格式,用于元组的第一个值(即:“apple”)。该值将被打印为 10 个字符,由于“apple”仅包含 5 个字符,因此会在其前面填充 5 个空格。
- 第二个占位符“%8.2f”表示浮点数格式,用于元组的第二个值(即:6.056)。“%”之后是字符串应包含的总位数(即:8,包括了小数点和所有数字),随后的“.2”表示浮点数的精度为 2 位,最后一个字符“f”代表“float”。
根据输出结果可知,“apple”前面的确有 5 个空格。而 6.056 为保留 2 位小数进行了四舍五入(变为了 6.06),为满足 8 个字符,所以数字前面添加了 4 个空格。
2
还有些什么?
有意思吧,快来用程序实际验证一下:
>>> print('fruit:%10s, price:%8.2f' % ('apple', 6.056))
fruit: apple, price: 6.06
不出意外,和上面分析的完全一致!但需要注意的是,格式化不是 print 函数的一部分。
Tip:
如果仔细查看示例,你会发现我们向 print 函数传递了一个格式化的字符串。或者换句话说:如果格式符“%”应用于一个字符串,它也将返回一个字符串,我们只不过是把这个字符串传递给了 print 函数。
所以,也可以先创建一个格式化的字符串,并将它分配给一个变量,然后将这个变量传递给 print 函数:
>>> s = 'fruit:%10s, price:%8.2f' % ('apple', 6.056)
>>> print(s)
fruit: apple, price: 6.06
因此,格式化是属于字符串的,而非 print 函数。
3
格式化符号
Python 支持多种格式化符号,每一种都代表着不同的数据类型:
格式化符号 | 描述 |
%d | 有符号整数(十进制) |
%i | 有符号整数(十进制) |
%o | 无符号整数(八进制) |
%u | 无符号整数(十进制) |
%x | 无符号整数(十六进制 - 小写) |
%X | 无符号整数(十六进制 - 大写) |
%e | 浮点指数格式(小写) |
%E | 浮点指数格式(大写) |
%f | 浮点数(用小数点表示) |
%F | 同上 |
%g | 浮点数字(根据大小采用 %e 或者 %f) |
%G | 浮点数字(根据大小采用 %E 或者 %F) |
%c | 字符及其 ASII 码 |
%r | 字符串(用 repr() 转换任何 Python 对象) |
%s | 字符串(用 str() 转换任何 Python 对象) |
%% | 字符 % |
根据上面的原理,使用起来会很容易:
# 浮点指数格式
>>> print('%10.3e' % 35.04567)
3.505e+01
>>> print('%10.3E' % 35.04567)
3.505E+01
# 无符号整数(八进制)
>>> print('%10o' % 15)
17
>>> print('%10.3o' % 15)
017
# 无符号整数(十六进制)
>>> print('%5x' % 47)
2f
>>> print('%5.4x' % 47)
002f
>>> print('%5.4X' % 47)
002F
# 字符 %
>>> print('sign: %%' % ())
sign: %
4
辅助符号
除了上面介绍的用法之外,“%”也经常会和辅助符号一起使用:
辅助符号 | 含义 |
* | 定义宽度或者小数点精度 |
- | 用作左对齐 |
+ | 在正数前面显示加号(+) |
# | 在八进制数前面显示零(0),在十六进制前面显示“ox”或者“0X”(取决于用的是“x”还是“X”) |
0 | 显示的数字前面填充“0”,而不是默认的空格。 |
(var) | 映射变量(通常用来处理字段类型的参数) |
m.n | m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)。 |
来看一些简单的示例:
# 十六进制数
>>> num = 50
>>> print('hex is %x' % num)
hex is 32
>>> print('hex is %X' % num)
hex is 32
>>> print('hex is %#x' % num)
hex is 0x32
>>> print('hex is %#X' % num)
hex is 0X32
# 正数前显示加号(+)
>>> print('%+d' % 20)
+20
# 数字前面填充空格或者 0
>>> print('% 5d' % 5)
5
>>> print('%05d' % 5)
00005
>>> print('%05d' % -5)
-0005
# m.n 浮点数
>>> pi = 3.141592653
>>> print('pi is %.4f' % pi)
pi is 3.1416
# 指定宽度和对齐
>>> name = 'Waleon'
>>> age = 18
>>> print('name:%10s, age:%10d' %(name, age))
name: Waleon, age: 18
>>> print('name:%-10s, age:%-10d' %(name, age))
name:Waleon , age:18
>>> print('name:%*s, age:%*d' %(10, name, 10, age))
name: Waleon, age: 18
>>>
# dict 参数
>>> person = {'name':'Waleon', 'age':18}
>>> print('%(name)s is %(age)d' % person)
Waleon is 18
也许有人会问:既然有了 str.format(),为什么还要介绍“%”?好吧,我来告诉你:
从 Python 2.6 之后,应该尽量使用 str.format() 方法,而不是这种老格式。
不幸的是,“%”在 Python 3.x 中仍然可用,而且还被广泛使用。所以呢,这就是要介绍它的原因。当在一些 Python 代码中遇到它时,最起码要能够理解它,是吧!但也许在将来的某一天,这种老式格式会被删除,因此还是建议多使用 str.format()。
·END·
高效程序员
谈天 · 说地 · 侃代码 · 开车
长按识别二维码,解锁更多精彩内容