Python 88 - String Formatting
# 前置知识
在阅读本文档前,请确保你已经掌握有关字符串的基础语法,详见 Python 语言的 88 - String 文档。
# 前言
字符串格式化是 Python 中常用的字符串处理手段之一,类似于 C/C++ 中的 sprintf ,但是在 Python 特性的支撑下,用起来毫无疑问要比 sprintf 方便得多。
# 字符串格式化
# 基本概念
字符串格式化 (string formatting) 在 Python 中指的是通过 str.format(...)
方法生成字符串 str
的一个副本,然后对其进行进行格式化的字段替换。例如:
s = 'hello, {name} : {id:04d}'
id = 24
print(s.format(name='alice', id=id))
hello, alice : 0024
被格式化的字符串被称为 format string ,需要遵循特定的格式以便于通过 format
方法执行格式化操作。具体地讲:
字符串中由大括号
{}
包裹的内容被称为 替换字段 (replacement fields) ,根据字段中的内容以及调用format
方法时传入的参数决定将其替换后的内容。除替换字段之外的内容均视为普通文本,按照与一般字符串相同的方式处理。
使用双大括号
{{
和}}
来表示原始的{
和}
以避免被解析为替换字段。
# 基础语法
替换字段的语法规则如下:
{[field_name] [! conversion] [: format_spec]}
其中 field_name
为指示替换内容的标识名称,可以使用位置参数或命名参数;conversion
和 format_spec
分别为转换域和格式规范域,详见下文。
# 位置参数
位置参数 (positional argument) :将数字 0
, 1
, 2
, ... 填入替换字段中,使其与调用 format
方法时传入的第 , , , 个参数相对应。例如:
a, b, c = 1, 'kk', 3
s = '{0} {2} {1}'.format(a, b, c)
print(s)
1 3 kk
位置参数可以省略,此时 0
, 1
, 2
, ... 将从左到右依次填入 format string 中的每个空字段 {}
,例如:
s1 = '{} {}'.format(a, b)
s2 = '{0} {1}'.format(a, b)
assert(s1 == s2)
但是不能同时使用显式和缺省的位置参数:
s = '{0} {} {1}'.format('a', 5)
line 1, ValueError: cannot switch from manual field specification to automatic field numbering
# 命名参数
命名参数 (named argument) :
TBD. 先学 python 函数调用,参数,属性,了解定义名词
>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
# 注意事项
无论是位置参数还是命名参数,同一参数均可在 format string 中被多次使用,例如:
a, b = 1, 2
s = '{0} {1} {1} {0}'.format(a, b)
print(s)
1 2 2 1
无论是位置参数还是命名参数,均可使用 .name
形式的表达式获取对应属性,或是使用 [index]
形式的表达式查找索引(实际上是调用 getattr()
或 __getitem__()
来查找的)。例如:
obj =
arr =
print('{0.name} {1[2]}'.format(obj, arr))
print('{obj.name} {array[2]}'.format(obj=obj, array=arr))
foo bar
foo bar
位置参数和命名参数可以共存,只有未指定关键字的参数才会被识别为位置参数,例如:
a, b = 1, 2
s = '{0} {1} {x}'.format(a, b, x = a + b)
print(s)
s = '{0} {1} {2}'.format(1, 2, x=3)
1 2 3
line 4, IndexError: Replacement index 2 out of range for positional args tuple
不过出于代码可读性的原因,通常不推荐混用两种参数格式,除非是在确实合理需要的场合。
# 转换域
转换域是跟在标识名称之后的、可选的 !
后缀,表示在进行字段替换之前要先对即将被替换进来的目标执行一个转换函数。目前仅支持三种转换域:
使用
!s
将调用str()
方法。使用
!r
将调用repr()
方法。使用
!a
将调用ascii()
方法。
所有类型的标识名称均可使用转换域,例如:
name = 'alice'
print('hello, {0}, {0!r}'.format(name))
print('hello, {!r}'.format(name))
print('hello, {name}, {name!r}'.format(name=name))
hello, alice, 'alice'
hello, 'alice'
hello, alice, 'alice'
# 格式规范域
格式规范域是跟在转换域之后(如果转换域为空则直接跟在标识名称之后)的、可选的 :
后缀,指示了字段内容的显示格式,包括字段宽度、对齐方式、填充、小数精度等。例如:
print('{x} {x:04d}'.format(x=12))
0012
用于描述格式规范域的语言被称为 格式规范迷你语言 (format specification mini-language) 。大多数内置类型都使用一种通用的格式规范语言,除此之外,可以为任意类型指定某种自定义的格式规范语言。
默认情况下,如果格式规范域为空,则格式化的结果与直接调用 str()
时产生的结果相同。自定义的格式规范语言可以违背该约定,但推荐尽量遵守。
# 通用格式规范
通用格式规范语言的语法规则如下:
[[fill]align][sign][#][0][width][grouping_option][.precision][type]
为便于描述,我们不会从左到右依次介绍每一项,而是根据各项之间的依赖关系以及各项的重要程度来决定顺序。
为便于描述,本文省略了一些不常用的信息。有关通用格式规范的全部内容,请参阅官方文档。
https://docs.python.org/3/library/string.html#format-string-syntax
# type
type
指示了字段值将被解析为哪种类型,是最基本的格式化规则。其格式类似于 C/C++ 中的 format 格式,例如 s
表示字符串。
未指定 type
时,number 类型将被视为其对应的基本类型,字符串和 object 类型将被视为字符串。也就是说,输出字符串时可以省略 s
。
对于整数类型,type
可选的合法值如下,省略时默认为 d
:
c
:整数值对应的 Unicode 字符。b
,o
,d
:依次为二进制、八进制、十进制。x
,X
:十六进制,分别使用小写和大写字母来表示大于 9 的数位以及由#
产生的前缀。
对于浮点数类型,type
可选的合法值如下,省略时默认为 g
:
f
,F
:定点表示法,默认精度为 位,分别使用小写和大写字母来表示nan
,NAN
和inf
,INF
。e
,E
:形如xey
和xEy
的科学计数法,分别使用小写和大写字母。g
,G
:通用的格式,对于给定的精度 ,这会将数字四舍五入为 个有效数字,然后根据其大小将结果格式化为定点表示法或科学记数法,分别使用小写和大写字母。有关该格式的详细规则,请参阅官方文档。%
:表示为百分比形式,将数值乘以 后以f
格式显示,并以百分号%
为后缀。
# width
width 是定义最小总字段宽度的十进制整数,包括任何前缀、分隔符和其他格式字符。如果未指定,则字段宽度将由内容决定。
# align
align
指示了字段值的对齐方式。当指定的 align
值合法时,可选用 fill
指示“空白区域”的填充字符(必须是单个字符),默认为空格填充。
align
可选的合法值包括:
<
:强制左对齐(在该字段的可用宽度范围内进行对齐,下同)。>
:强制右对齐。^
:强制居中。=
:对于 number 类型,如果显示符号,则强制将填充放在符号和数字之间,例如格式规范域=0d
以-000120
的形式输出字段值-120
。
未指定 width
时,由于默认宽度为输出内容的实际长度,align
不会产生实际效果。
未指定 align
时,number 类型默认为右对齐,绝大多数 object 类型默认为左对齐。
未指定 align
时,在宽度字段前面加上一个零 ('0') 字符(即语法规则中的 [0]
部分)会启用数字类型的符号感知零填充。这等效于填充字符“0”,对齐类型为“=”。
# 其它
grouping_option
grouping_option
仅对 number 类型有效,指示了所使用的千分位分隔符,可选的合法值包括 ,
和 _
。
sign
sign
仅对 number 类型有效,指示了显示符号的方式,可选的合法值包括:
-
:仅对负数显示符号(默认选项)。+
:对正负数均显示符号。空格 :对负数显示负号,对正数使用前导空格。
#
#
仅对整数、浮点数和复数类型有效,并且为不同类型的字段使用 #
有不同的效果:
对于整数类型,当使用二进制、八进制或十六进制输出时,会在输出数值前输出前缀
0b
,0o
,0x
或0X
。对于浮点数和复数类型,会在输出取值为整数的数值时也带上小数点,例如
12.0
。
precision
precision
仅对浮点数和复数类型有效,指示了显示浮点数的精度,以 .
为前缀。
# 自定义格式规范
TBD.
# 代码示例
这里给出了大量的示例,以期能帮助读者更透彻地理解字符串格式化。
TBD. add much more samples with explanations.
下面是来自 Python 3.10 官方文档的一组基础语法示例:
"First, thou shalt count to {0}" # References first positional argument
"Bring me a {}" # Implicitly references the first positional argument
"From {} to {}" # Same as "From {0} to {1}"
"My quest is {name}" # References keyword argument 'name'
"Weight in tons {0.weight}" # 'weight' attribute of first positional arg
"Units destroyed: {players[0]}" # First element of keyword argument 'players'.
>>> '{2}, {1}, {0}'.format(*'abc')
'c, b, a'
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'
d = dict(x='xx', y='yy')
print('{x} {y}'.format(**d))
# f-string
# 基本概念
格式化字符串常量 (formatted string literal, f-string) 是一种在运行时刻生成的字符串常量,通过对字符串进行格式化的字段替换产生。f-string 以 f
或 F
为前缀标识,例如:
name = 'alice'
print(f'hello, {name}')
hello, alice
f-string 和 str.format(...)
具有类似的功能,但二者并不等价,例如:
f-string 直接以名称指定用以替换字段的变量,而不需要在调用
format
方法时传入参数以协同指定。f-string 产生的是一个字符串常量,而不是字符串
str
的副本。f-string 和 format string 的格式规范基本相同,例如同样具有由大括号
{}
包裹的替换字段,但是稍微有些不同。
# 格式规范扩充
f-string 的格式规范与 format string 基本相同,但是稍微有些不同。
从 Python 3.7 开始,在表达式后方接等号 =
能够便捷地以 name=var
的形式显示变量或表达式的值。这是一种很常见的需求,该功能使得我们无需输入两遍表达式的名称,例如:
foo, bar = 'fff', 'bbb'
print(f'foo={foo}, hello') # redundant foos
print(f'{foo=}, hello') # only 1 foo
print(f'{foo = }, hello') # spaces are kept
print(f'{foo + bar = }') # expression is also ok
foo=fff, hello
foo='fff', hello
foo = 'fff', hello
foo + bar = 'fffbbb', hello
# 旧式语法
这种旧式的字符串格式化语法源自 Python 2.x 时代,被称为 printf-style string formatting ,由于具有多种缺陷(例如不能正常显示元组和字典),目前已经不建议使用,其所有功能均可被 str.format(...)
或 f-string 更好地替代。
旧式语法的基本格式为 format % values
,其中 format
是格式字符串,values
是用于对 format
的内容执行替换的元组或字典。
有关旧式语法的更多内容,请参阅官方文档。
https://docs.python.org/3/library/stdtypes.html#old-string-formatting