所谓格式化,指将现有的数据组成得到一个完整的字符串用于输出、传参等的方式。Python2中,通常使用百分号的方式来对字符串进行格式化操作。例如:
这种方式来源于C语言的 printf()
等所使用的转换说明,这么做不够灵活,格式化较为麻烦。Python3中更新了一种更为现代化的格式化方法,可以更方便地达到预期的输出效果。
Python3中的格式化
使用str.format()方法
Python3中格式化的基本思路是:在字符串中待格式数据用花括号对“ {}
”占位,在格式化时再用实际的内容替换。str.format()
方法告诉字符串中的花括号对用哪些数据替换。该方法格式化的一个基本示例为:
使用这种方式对字符串格式化更加强大。在这个基本的示例中,它也非常直观地表明了如何进行格式化。
使用 str.format()
格式化的第一个优点是,它能充分利用提供的数据。
例如,可以在花括号内设置一个整数,代表使用哪一个格式数据填充这部分内容:
除了这种按位置的接收参数方式,还可以使用按关键字的接收参数方式:
它们可以在同一个格式字符串中混合使用。
由于字符串内的花括号被用来确定格式数据的位置,可以用重复的花括号“ {{
”和“ }}
”来代表格式字符串内原始的花括号字符:
百分号格式字符串支持的调整精度、宽度、对齐、符号等,str.format()
也全部支持。以下是部分示例:
格式化的完整语法
一个花括号内可以包含许多控制用的说明,它们决定了如何对填充的内容设置格式。格式化修饰符的完整语法为:
{[key][!flag][:[[fill]align][sign][#][0][minwidth][.precision][type]]}
方括号代表里面的内容作为整体是可选的。注意它们从左至右的位置。
key
代表用哪一个数据来填入该位置:
它可以是整数,也可以是标识符。由于格式方法的完整结构是 str.format(self, *args, **kwargs)
,整数告诉格式字符串从 args
元组内寻找元素,标识符告诉格式字符串从 kwargs
字典内寻找元素。
这种方式直接引用的对象,甚至可以再次通过“ .
”运算符或“ []
”运算符取值:
!flag
是一个显式转换标志。这个显式转换标志用于最先对被格式的数据变为标准的字符串对象:
!s
会用 str()
函数处理数据,得到对象的详细信息;!r
会用 repr()
函数处理数据,得到对象的描述信息;!a
会用 acsii()
函数处理数据,得到 ASCII 字符串。
例如,如果要让替换的字符串加上引号,可以使用 !r
修饰它:
接下来的冒号后面引导了一些标准的格式说明符(format specifier),它们有:
align
代表在该位置比较宽时,数据是如何对齐的。该选项提供的值有:
< | 左对齐 |
> | 右对齐 |
^ | 居中对齐 |
= | 一种对数字的特殊对齐方式,数字右对齐,但符号在最左侧 |
对最后一种对齐方式的直观演示如下:
- 如果给定了对齐方式,那么
fill
表示对齐后剩下的位置该填充什么字符。默认情况下,剩余的部分用空格代替。
对以上格式化稍作修改,它会美观很多:
sign
选项告诉格式字符串如何处理数字的符号位:
+ | 正数前面加上正号“ + ”,负数前面加上符号“ - ” |
- | 只需要在负数前加上负号“ - ”即可 |
空格 | 在负数前加上负号“ - ”;同时为了对齐,在正数前加一个空格 |
#
字符如果使用,可以处理不同进制的数字,在前面加上“0b
”、“0o
”、“0x
”等前缀。
minwidth
选项代表该位置的最小宽度:
前面的对齐和填充选项就是基于该最小宽度设置的。如果格式后该位置拥有的字符数仍然无法填满这个最小宽度,那么对齐和填充才有意义。
所谓的“最小”表示如果已经比这个最小值还宽了,那就可以忽略它,按正常的宽度排列内容。
还有一种特殊的情况是,如果该宽度值被写成“ 0
”打头的数字,那么它会使用一种特殊的“零填充(zero-padding)”方式。具体来说,它等价于使用“ =
”的对齐并用“
”字符填充。例如:0
.precision
表示小数显示多少位数。如果不用在小数上,表示最多显示多少字符。
type
选项告诉格式字符串数据用什么类型展示:
对于整数,可以用以下选项将它解释成:
b | 二进制数字 | d (默认) | 十进制数字 |
o | 八进制数字 | c | 对应位置的Unicode字符 |
x | 十六进制数字 | n | 数字。相比通用的 d 选项,它可能会根据本地化做一些表示方面的调整 |
X | 全部大写的十六进制数字,包括可能的前缀 |
对于浮点数,可以用以下选项将它解释成:
e | 使用带“ e ”的科学计数法表示浮点数 |
g (默认) | 哪种方式表示更清晰,就用哪种方式 |
E | 大写版本的“ e ” |
G | 大写版本的“ g ” |
f | 使用小数点形式表示浮点数 | n | 浮点数。相比通用的 g 选项,它可能会根据本地化做一些表示方面的调整 |
F | 大写版本的“ f ” |
% | 百分小数格式,会在后面加上百分号 |
以上就是Python3字符串格式化的完整格式语法,这种语法相比百分号格式更加强大。
这种语法的强大之处就在于,甚至可以通过嵌套花括号,来动态调整格式化:
使用这种格式化方式,还可以自行决定如何格式化一个对象。下文会提到这种方法。
使用f-string
Python3.6 中新增了一种语法,称为 f-string ,它在保持这种格式化语法的强大性的同时,更加简洁、直观。
f-string即在正常的字符串字面量前面加上一个“ f
”。这种字符串可以直接在表示时便被格式化:
注意,这里直接引用了上下文的对象,或者说一个表达式的值,将这个表达式的值用于格式化。
可以用上文中提到的语法对该表达式的值进行格式化处理:
f-string 不仅可以用于这种普通的字符串,还可以用于三个引号对构成的多行字符串,具体的使用方法与普通字符串是一致的。
f-string 和原始字符串可以共用,形成一种特殊的 fr 字符串:
起始符 f 和 r 的顺序以及大小写都无所谓。f 修饰符会优先起作用,将字符串中的占位符换成需要的内容。
f-string 简洁强大,在大多数即格式即用的时候非常好用。
自定义格式化
可以根据自己的类型,确定如何对数据进行格式化。例如,Python内置的日期时间类型就支持一种对日期时间处理的特殊格式化:
如果自定义的类需要自定义的字符串格式方法,那么它需要实现特殊方法 __format__()
。该方法的标准结构为:
在进行字符串格式化时,冒号后面的转换说明符会传递给 format_spec
参数,这样对象就可以借助该参数中的内容,做一些合适的处理,返回一个字符串以供格式化。
注意:如果使用“ !
”显式转换,那么经过显式转换后,该对象已经变成字符串类型,因此后面需要使用字符串的转换说明符格式。
下面提供了一个示例,给该类的使用者提供了自行格式化的方式:
下面是一个使用示例:
获得的结果为:
最后,Python3内置了一个函数 format(value, format_spec)
,本质上就是调用对象的 __format__()
方法,来表示一个对象被格式化后的结果。
至此,可以总结出Python3字符串格式化的一般规律了:
花括号对“ {}
”表示格式后的内容将放在这里;
花括号内,最开头的一部分表示需要对什么数据执行格式化。它可能是一个外部的变量、.format()
的一个参数,或它们参与的表达式计算后的结果;
接下来“ !
”的部分决定是否需要调用显式转换,如果使用这一步,该数据将先一步按照某些方式转换为标准的字符串;
最后,“ :
”后面的部分是转换说明符,这部分内容将决定一个对象如何进行最终的格式化。对于 str
对象的转换说明符语法,可以参见前文的详细介绍,并在使用时查阅即可。
总体来说,字符串的格式化作为一种Python标准的语法,不需要深入研究它,只需要明白它的基本工作原理,真正要用到的时候只需要查阅它的细节即可。
参考资料
https://docs.python.org/3.10/library/string.html#format-string-syntax
Python3标准库 string
,介绍字符串是如何格式与被格式的
https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals
从词法分析的角度介绍了格式化字符串字面量的原理
https://docs.python.org/3/reference/datamodel.html#object.format
介绍对象的格式化模型
https://www.python.org/dev/peps/pep-3101/
一篇非常优质的关于Python3字符串格式化的讨论