字符串格式化对于每个语言来说都是一个非常基础和常用的功能,学习 Python 的同学大概都知道可以用%语法来格式化字符串。然而为了让我们更方便的使用这个常用功能,语言本身也在对字符串格式化方法进行迭代。

Python 2.6 以前:%操作符

在 Python 2.6 出现之前,字符串迭代只有一种方法,就是%(也是取模)操作符,%操作符支持 unicode 和 str 类型的 Python 字符串,效果和 C 语言中的 sprintf()方法相似,下面是一个使用%格式化字符串的例子:

print("I'm %s. I'm %d year old" % ('Tom', 27))

%符号前面使用一个字符串作为模板,模板中有标记格式的占位符号,%后面是一个 tuple 或者 dict,用来传递需要格式化的值。占位符控制着显示的格式,下面列表展示了占位符的种类:

占位符内容
%d十进制整数
%i十进制整数
%o八进制整数
%u无符号整数
%x无符号十六进制(小写)
%X无符号十六进制(大写)
%e浮点型(科学记数法,小写)
%E浮点型(科学记数法,大写)
%f浮点数
%F浮点数
%g浮点型,如果小数位数超过 4 位,使用科学记数法表示(小写)
%G浮点型,如果小数位数超过 4 位,使用科学记数法表示(大写)
%c单个字符
%r字符串(调用 repr()方法生成)
%s字符串(调用 str()方法生成)

除了对数据类型的指定,%操作符还支持更复杂的格式控制:

%[数据名称][对齐标志][宽度].[精度]类型
名称内容
数据名称数据名称用于字典赋值,如果%符号后面传递的数组就不需要填写了
对齐标志有+、-、0、‘ ’四种,+表示显示正负数符号,-表示左对齐,空格表示在左侧填充一个空格,0 表示用 0 填充
宽度表示格式化后的字符串长度,位数不足用 0 或空格补齐
精度小数点后的位数
类型数据类型(参考占位符种类)

例如 print(’%053f’ % ‘12.34’)会输出 0012.340

Python 2.6:format 函数

到 Python2.6 时,出现了一种新的字符串格式化方式,str.format()函数,相比于%操作符,format 函数使用{}和:代替了%,威力更加强大,在映射关系方面,format 函数支持位置映射、关键字映射、对象属性映射、下标映射等多种方式,不仅参数可以不按顺序,也可以不用参数或者一个参数使用多次,下面通过几个例子来说明。

'{1} {0}'.format('abc', 123# 可以不按顺序进行位置映射,输出'123 abc'

'{} {}'.format('abc', 123# 可以不指定参数名称,输出'abc 123'

'{1} {0} {1}'.format('abc', 123# 参数可以使用多次,输出'123 abc 123'

'{name} {age}'.format(name='tom', age=27# 可以按关键字映射,输出'tom 27'

'{person.name} {person.age}'.format(person=person)  # 可以按对象属性映射,输出'tom 27'

'{0[1]} {0[0]}'.format(lst)  # 通过下标映射

可以看到,format 函数比%操作符使用起来更加方便,不需要记住太多各种占位符代表的意义,代码可读性也更高。在复杂格式控制方面,format 函数也提供了更加强大的控制方式:

[[填充字符]对齐方式][符号标志][#][宽度][,][.精度][类型]

例如:

'{:S^+#016,.2f}'.format(1234)  # 输出'SSS+1,234.00SSSS'

我们以上面的代码为例,通过表格说明一下 format 格式控制参数:

类型说明示例说明
填充字符不填时默认用空格填充S 表示用 S 填充
对齐方式^表示居中对齐、<表示左对齐、>表示右对齐^表示居中对齐,左右位数不足部分会用填充字符填充
符号标志+表示有符号(正数前显示+,负数前显示-),空格表示整数前加一个空格以和负数对齐+表示正数前显示空格
#表示是否在二进制、八进制、十六进制前显示 0b、0o、0x 等符号#表示显示进制符号,由于是十进制,所以不显示
宽度表示输出字符串的宽度16 表示字符串宽度为 16,不足部分会补齐
,表示使用,作为千位分隔符,表示使用千位分隔符
精度表示小数点后数字位数.2 表示精度为 2 为
类型s 表示字符串类型,c 表示字符类型,b\o\d 分别表示二八十进制,x\X 表示小写和大写十六进制,e\E 表示小写和大写的科学记数法,f 表示浮点型f 表示浮点型数字

可以看到 format 函数在%基础上丰富了格式控制种类,并且使输出更容易。

Python 3.6:f-string

不少使用过 ES6 的小伙伴会知道其中的模板字符串,采用直接在字符串中内嵌变量的方式进行字符串格式化操作,Python 在 3.6 版本中也为我们带来了类似的功能:Formatted String Literals(字面量格式化字符串),简称 f-string。

f-string 就是以 f’‘开头的字符串,类似 u’‘和 b’’,字符串内容和 format 方法中的格式一样,但是可以直接将变量带入到字符串中,可读性进一步增加,例如:

amount = 1234
f'请转账给我{amount:,.2f}元'  # '请转账给我1,234.00元'

同时,f-string 的性能是比%和 format 都有提升的,我们做一个简单的测试,分别使用%操作符、format 和 f-string 将下面语句执行 10000 次:

'My name is %s and i'm %s years old.' % (name, age)
'My name is {} and i'm {} years old.'.format(name, age)
f'My name is {name} and i'm {age} years old.'

用时结果如下:

总结

如果你的项目使用的 Python 版本已经提升到 3.6,f-string 格式化是首选方式,不仅在保持功能强大的同时语义上更容易理解,而且性能也有较大的提升。如果项目还没有提升到 3.6 或者使用的 2.7,更建议使用 format,虽然性能上没有优势,但是语义上还是比%操作符更加便于理解的,功能也更加强大。