字符串格式化
第 2 课就用上了 f-string,第 3 课用过 :.2f。那个冒号后面其实是一套小语法,叫格式说明符:小数位、分隔符、宽度、对齐都由它管,而值本身不变。这一课一样一样地讲,最后排一张整齐的表。
格式说明符
花括号里,前面是值,冒号后面是格式说明符:{值:说明符}。说明符只改值显示的样子。
1price = 1234567.8912print(f"{price}")3print(f"{price:.2f}")4print(f"{price:.0f}")5print(f"{price:,.2f}")6print(f"{price:_.2f}")
1234567.891 1234567.89 1234568 1,234,567.89 1_234_567.89
.2f 是「定点小数,保留两位」。前面加逗号,就每三位加一个千分位逗号;换成下划线,就用 _ 分隔。整数也能用:f"{5000000:,}" 得到 5,000,000。
最后写一个 %,就把小数显示成百分比:先乘 100,再加上百分号,小数位照你写的来。
1done = 72total = 83print(f"{done / total:%}")4print(f"{done / total:.1%}")5print(f"{done / total:.0%}")
87.500000% 87.5% 88%
这行会显示什么?
1print(f"{2 / 3:.0%}") % 先乘 100,2 / 3 变成 66.66...,再按 .0 取到整数:67%。
宽度、对齐和填充
说明符里的一个数是宽度:最少占几个字符。值不够长,就用空格补上。下面两边的竖线标出每个值从哪开始、到哪结束。
1print(f"|{'oil':8}|")2print(f"|{42:8}|")3print(f"|{'oil':>8}|")4print(f"|{'oil':^8}|")5print(f"|{42:<8}|")6print(f"|{'lighthouse':4}|")
|oil | | 42| | oil| | oil | |42 | |lighthouse|
文字默认靠左,数字默认靠右。<、>、^ 分别是靠左、靠右、居中。宽度只是「最少」:'lighthouse' 比 4 长,就整个显示出来。
在对齐符号前面放一个字符,就用它代替空格来补,这叫填充字符。
1print(f"{'库存':*^15}")2print(f"{'灯油':.<12}340")3print(f"{7:0>3}")4print(f"{7:03}")5print(f"{-7:05}")
******库存******* 灯油..........340 007 007 -0007
0>3 是在左边补 0。数字还有个简写:宽度前面直接写 0,比如 03,也是补 0,而且负号会留在最前面。
正负号和其他进制
默认只有负数带符号。+ 让正数也带上 +;写一个空格,正数前面留一个空位,正数负数就能对齐。
1print(f"{5:+} {-5:+}")2print(f"{5: } {-5: }")3print(f"{255:b} {255:o} {255:x} {255:X}")4print(f"{255:#x} {255:#b}")5print(f"{5:08b}")6print(f"{1234567:.2e}")
+5 -5 5 -5 11111111 377 ff FF 0xff 0b11111111 00000101 1.23e+06
| 字母 | 显示成 | 255 变成 |
|---|---|---|
b | 二进制 | 11111111 |
o | 八进制 | 377 |
x / X | 十六进制 | ff / FF |
e | 科学计数法 | 2.550000e+02 |
# 加上 Python 代码里用的前缀(0x、0b、0o)。几部分的顺序是固定的:填充和对齐、正负号、#、0、宽度、分隔符、.小数位、字母。08b 就是「补 0 到 8 位,用二进制」。
排一张整齐的表
表头和每一行,同一列用同样的宽度和对齐,列就对齐了。一般文字列靠左,数字列靠右。
1stock = [("lamps", 12, 1.5), ("oil", 340, 0.25), ("wicks", 5, 12.0)]2print(f"{'Item':<8}{'Qty':>6}{'Price':>8}")3print("-" * 22)4for name, qty, price in stock:5 print(f"{name:<8}{qty:>6}{price:>8.2f}")
Item Qty Price ---------------------- lamps 12 1.50 oil 340 0.25 wicks 5 12.00
表头不用小数,但宽度一样:8、6、8。每一行的单价多加了 .2f,小数点也对齐了。这里的名字特意用了英文,原因见下面的小技巧。点单步,看每一行是怎么拼出来的。
小技巧: 宽度按字符个数算,一个汉字算 1 个,可屏幕上一个汉字差不多有两个英文字母宽。所以带汉字的表格,代码没错也可能对不齐。
用 = 调试
在表达式后面加 =,f-string 会显示表达式本身、一个等号和它的值。想看看一个变量里装的是什么,这样最快。
1lamps = 122name = "Wick"3share = 2 / 34print(f"{lamps=}")5print(f"{name=}")6print(f"{lamps * 3 = }")7print(f"{share=:.2f}")
lamps=12 name='Wick' lamps * 3 = 36 share=0.67
字符串会带着引号显示,多了个空格一眼就能看出来。= 两边的空格会原样留在输出里;要加说明符,照样写在冒号后面。
宽度用变量
宽度和小数位也可以来自变量:在说明符里再套一对花括号。
1names = ["oil", "lamps", "lighthouse"]2w = max([len(n) for n in names])3for n in names:4 print(f"{n:>{w}}|")5digits = 36print(f"{3.14159:.{digits}f}")
oil|
lamps|
lighthouse|
3.142
这里最长的名字决定宽度,列表里换什么名字,都排得下。
老写法
别人的代码里还会看到两种老写法。format() 和 str.format 的说明符和 f-string 是同一套;% 有自己的一套,写法相近,比如 %.2f、%5d。
1print(format(1234.5, ",.2f"))2print("{}有{}盏灯".format("Wick", 12))3print("{0}、{1}、{0}".format("开", "关"))4print("{name:>6}|".format(name="oil"))5print("%s有%d盏灯" % ("Wick", 12))6print("%.2f 和 %5d|" % (3.14159, 42))
1,234.50 Wick有12盏灯 开、关、开 oil| Wick有12盏灯 3.14 和 42|
| 写法 | 例子 |
|---|---|
| f-string(推荐) | f"{x:.2f}" |
format() 函数 | format(x, ".2f") |
str.format | "{:.2f}".format(x) |
% 运算符 | "%.2f" % x |
format(值, 说明符) 排一个值。str.format 按顺序填每个 {},也可以按编号或名字填。% 是最老的:%s 放任何值,%d 放整数,%.2f 放小数,值不止一个时用元组。写新代码,f-string 最短也最清楚。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。
一大笔钱
✓把合计显示成带千分位、两位小数的样子。
合计:¥1,234,567.89
1total = 1234567.8912print(f"合计:¥{total}")
进度
✓显示 完成:,后面跟着完成了多少,用保留一位小数的百分比。
完成:87.5%
1done = 72total = 83print(done, total)
星号标题
✓让 title 在一行星号中间居中。宽度用 width,改了它,这一行跟着变。
****库存****
1title = "库存"2width = 103print(title)
这一课学会了
{值:说明符}只改值显示的样子。.2f定小数位,,或_加千分位,%显示百分比。- 一个数定宽度;
<>^定对齐;它们前面的字符是填充;03补 0。 +或空格管正负号;b、o、x、e显示其他进制和科学计数法。- 表头和每行用同样的宽度,表格就对齐了。
f"{x=}"显示表达式和它的值,调试很方便。{n:>{w}}让宽度来自变量。format()和str.format是老写法,说明符一样;%用相近的写法,比如%.2f。