目录
一、绪论
二、%
2.1 示例
2.2 速查表
三、format
3.1 示例
3.2 速查表 (数字格式化)
四、f-string
4.1 说明
4.2 示例
一、绪论
随着 Python 的更新,其 字符串格式化 功能也在不断地优化。在 Python 2.6 以前,% 操作符一枝独秀;在 Python 2.6 之后,迎来后起之秀format 操作符;在 Python 3.6 之际,更有 f-string 操作符异军突起。字符串格式化的逐步优化,不但简化了操作,而且提升了效率,如下执行时间对比柱状图所示:
可见,“远古时期” 的模板字符串 str.Template 过于低效,str.format 和 % 操作符在简便和效率之间有所权衡,而 f-string则具有 最佳性能。以下将逐一回顾:
二、%
2.1 示例
作为最古老格式化字符串方式,% 操作符与 C 中 sprintf 函数的语法基本相同,因而具有浓浓的 C 风味,使得最终的表达式可能较为复杂和冗长。关于 % 操作符的用法一言以蔽之 —— 在目标字符串中指定位置插入待填充内容的类型符号。例如:
>>> "%s is %d years old." % ('Zhang San', 18) # 直接使用
'Zhang San is 18 years old.'
# -------------------------------------------------------------------------
>>> name = 'Zhang San'
>>> age = 18
>>> "%s is %d years old." % (name, age) # 间接使用
'Zhang San is 18 years old.'
2.2 速查表
常用类型符号及其说明:
符号 | 说明 |
%s | 格式化字符串 |
%c | 格式化字符及其 ASCII 码 |
%d | 格式化整数 |
%u | 格式化无符号整型 |
%o | 格式化无符号八进制数 |
%x | 格式化无符号十六进制数 |
%X | 格式化无符号十六进制数 (大写) |
%f | 格式化浮点数,可指定小数点后的精度 |
%e | 格式化浮点数 (科学计数法) |
%E | 同 %e |
%g | %f 和 %e 的简写 |
%G | %F 和 %E 的简写 |
%p | 用十六进制数格式化变量的地址 |
辅助指令:
符号 | 说明 |
* | 定义宽度或小数点精度 |
- | 用于左对齐 |
+ | 正数前显示加号 '+' |
<sp> | 正数前显示空格 |
# | 八进制数前显示零 '0'、十六进制数前显示 '0x' 或 '0X' |
0 | 显示的数字前面填充'0'而不是默认的空格 |
% | '%%' 输出一个 '%' (百分号转义) |
(var) | 映射变量 (字典参数) |
m.n. | m 是显示的最小总宽度,n 是小数点后的保留位数 |
常用转义字符:
三、format
3.1 示例
相比于 % 操作符,str.format()
>>> "{} is {} years old.".format('Li Hua', 3) # 不指定位置索引, 默认排列
'Li Hua is 3 years old.'
# -------------------------------------------------------------------------
>>> "{0} is {1} years old.".format('Li Hua', 3) # 指定位置索引
'Li Hua is 3 years old.'
# -------------------------------------------------------------------------
>>> "{0} is {1}{1} years old.".format('Li Hua', 3) # 指定位置索引, 多次使用
'Li Hua is 33 years old.'
还可以对 str.format() 设定参数:(其中使用 * 和 ** 解包的原理详见文章 单/双星号操作符)
>>> "宿舍楼:{building}, 门牌号:{number}".format(building="鹏翔2斋", number=1234)
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info = {"building":"鹏翔2斋", "number":1234}
>>> "宿舍楼:{building}, 门牌号:{number}".format(**info) # 使用 ** 对 dict 解包
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info2 = ("鹏翔2斋", 1234)
>>> "宿舍楼:{}, 门牌号:{}".format(*info) # 使用 * 对 tuple 解包
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info3 = ["鹏翔2斋", 1234]
>>> "宿舍楼:{0[0]}, 门牌号:{0[1]}".format(info3) # 使用 index 指定 list 元素
'宿舍楼:鹏翔2斋, 门牌号:1234'
甚至可以向 str.format() 传入对象:
>>> class Num:
def __init__(self, num):
self.num = num
>>> six = Num(6)
>>> "my number is {0.num}".format(six) # 调用成员属性作为参数
'my number is 6'
以上实例足以说明 str.format() 的灵活与强大!
3.2 速查表 (数字格式化)
常见用法示例及其说明:
示例 | 格式 | 结果 | 说明 |
3.1415 | {:.2f} | 3.14 | 保留小数点后2位 |
2.7182 | {:+.2f} | +2.71 | 带符号保留小数点后2位 |
-1 | {:+.2f} | -1.00 | 带符号保留小数点后2位 |
1.2345 | {:.0f} | 1 | 删去小数部分 |
8 | {:x>2d} | 08 | 整数补x (填充左边, 宽度为2) |
16 | {:y<4d} | 16xx | 整数补y (填充右边, 宽度为4) |
1000000 | {:,} | 1,000,000 | , 作千分位分隔符 |
1000000 | {:_} | 1_000_000 | _ 作千分位分隔符 |
0.48 | {:.4%} | 48.0000% | 小数转百分比 |
100000000 | {:.2e} | 1.00e+08 | 指数记法 |
16 | {:>8d} | 16 | 向右对齐 (宽度为8) |
16 | {:<8d} | 16 | 向左对齐 (宽度为8) |
16 | {:^8d} | 16 | 居中对齐 (宽度为8) |
进制转换:(# 符号用于切换数字显示,可获取各进制的带前缀大、小写表示)
示例 | 格式 | 结果 | 说明 |
12 | {:#b} | 0b1100 | 带前缀 二进制小写表示 |
12 | {:b} | 1100 | 二进制表示 |
12 | {:o} | 14 | 八进制表示 |
12 | {:d} | 12 | 十进制表示 |
12 | {:x} | c | 十六进制表示 |
12 | {:#X} | 0XC | 带前缀 十六进制大写表示 |
事实上,str.format() 的用法远比上述示例复杂多样,详见官方文档:格式字符串语法。
四、f-string
4.1 说明
相较于前两种方法,Python 3.6 中的 f-string (格式化字符串常量 - formatted string literals),应为最佳形式 —— 简洁、易读,不仅有助于简化十分繁琐的写法,而且具有 最佳效率,非常建议使用。与具有恒定值的其它字符串常量不同,格式化字符串实际上是运行时运算求值的表达式。
f-string 的语法结构为:
f ' <text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ... '
其中,f (或 F) 为目标字符串前缀;<text> 表示占位符的上下文;类似于 str.format,目标字符串中的占位符 (一种运行时计算的表达式) 也使用了花括号 { },在其中必须加入表达式 <expression>,可选参数标志 !s 表示调用表达式上 str() (默认)、!r 表示调用表达式的 repr()、!a 表示调用表达式的 ascii()。最后,使用 format 协议格式化目标字符串。
4.2 示例
其常用方法是在目标字符串前加上字母 f 或 F,然后在目标字符串中插入占位符(直接在 { } 中加入变量)。例如:
>>> name = 'Bob'
>>> age = 24
>>> f"{name} is {age} years old." # 格式字符串前缀 f 或 F, 中间插入占位符 {variable}
'Bob is 24 years old.'
其实,花括号 { } 中可以灵活地填入 各种表达式,甚至可以 调用函数与类成员 等,而不仅仅局限于变量,例如:
>>> f"The result of the function is {2 * 3 + 4}" # 算术表达式 内联运算
'The result of the function is 9.43656365691809'
# ----------------------------------------------------------------------------
>>> f'My weapen is {weapen.upper()}' # 函数/方法调用
'My weapen is AK47'
# ----------------------------------------------------------------------------
>>> import math
>>> f"The result of the function is {2 * math.e + 4}" # 类成员(属性/方法)调用
'The result of the function is 9.43656365691809'
当然,除了内置函数和自定义普通函数,lambda 表达式 (匿名函数) 也可以填入 { },但为避免 lambda 表达式的分号 : 带来的歧义,应将 lambda 表达式置于圆括号 ( ) 中,例如:
>>> f'The test result is {lambda x: x + 1 (99)}' # 无法解析 End-of-File
SyntaxError: unexpected EOF while parsing
# ----------------------------------------------------------------------------
>>> f'The test result is {(lambda x: x + 1)(99)}' # 格式:{(lambda表达式)(lambda表达式参数)}
'The test result is 100'
为避免引号冲突,可以灵活使用 单引号 ' 、双引号 '' 、单引号文本字符串 ' ' '、双引号文本字符串 '' '' '' 来解决,只需 保证 目标字符串外定界符的引号 与 目标字符串中 占位符内的引号 不同。例如:
>>> f"We are {"CT"}" # 内外均使用了双引号 ""
SyntaxError: invalid syntax
# ----------------------------------------------------------------------------
>>> f"We are {'CT'}" # 内用单引号 '' 外用双引号 ""
'We are CT'
# ----------------------------------------------------------------------------
>>> f'''We are {'CT'} and you are {"T"} ''' # 内用单双 外用三
'We are CT and you are T '
# 不论怎么搭配, 只要内外不冲突即可
但注意,占位符 { } 内不能使用转义符号 \ 对引号转义 (因为不允许出现 \,除非用变量间接传递),而上下文可以:
>>> f'I think {you\'re powerful}' # {} 内不可使用转义符号 \
SyntaxError: f-string expression part cannot include a backslash
# ----------------------------------------------------------------------------
>>> f'You\'re powerful' # {} 外则可同正常字符串一样使用转义符号 \
"You're powerful"
# ----------------------------------------------------------------------------
>>> words = "you\'re powerful" # 除非用变量传递
>>> f'I think {words}'
"I think you're powerful"
此外,更多技术细节详见 官方文档。由于 f-string 是基于 str.format 发展而来的, str.format 所用符号同样适用于 f-string (所以可以使用 3.2 节的速查表)。
参考文献:
6.1. string — 常见的字符串操作 — Python 3.6.15 文档