一个格式化输出的例子
相应源码
看完示例,我们一起研究一下这个format函数到底什么鬼!
首先大家要知道,format函数是字符串对象的一个方法,也可以写为str.format(),它提供了非常强大的用于创建字符串的途径。对于简单的情况,使用str.format()方法是容易的,但是如果需要进行复杂的格式化操作,就要学习该方法需要的格式化语法。
str.format()方法会返回一个新字符串,在新字符串中,原字符串的替换字段被适当格式化后的参数所替代,例如;
>>> {0}语言{1}函数可以用来生成格式化字符串..format(python, format)
'python语言format函数可以用来生成格式化字符串.'
每个替换字段都是由包含在花括号中的字段名标识的。如果字段名是简单的整数,就将被作为传递给str.format()方法的一个参数的索引位置。因此,在这种情况下,名为0的字段被第一个参数所替代,名为1的字段则被第二个参数所替代。
如果需要在格式化字符串中包含花括号,就需要将其复写,下面看示例:
>>> {{{{{0}语言}}{1}函数}}可以用来生成格式化字符串。.format(python, format)
'{{python语言}format函数}可以用来生成格式化字符串。'
值得提醒的是,str.format()函数也可以用来连接字符串,作用同str.join()函数。
替换字段可以使用下面的任意一种语法格式:
1、{字段名}
2、{字段名!转换格式符}
3、{字段名:格式规约}
4、{字段名!转换格式符:格式规约}
先上例子,再继续说
四种语法格式示例
>>>#{字段名}
>>> '{0}'.format('hello world!')
'hello world!'
>>>#{字段名!转换格式符}
>>>'{0!a}'.format('战狼2')
'\战\狼2'
>>>#{字段名:格式化规约}
>>>'{0:a>30,.2f}'.format(1234567.876543)
'aaaaaaaaaaaaaaaaaa1,234,567.88'
>>>#{字段名!转换格式符:格式化规约}
>>>'{0!a:>30}'.format('战狼2')
'\战\狼2'
一、字段名
字段名或者是一个与某个str.format()方法参数对应的整数来确定位置,或者是方法的某个关键字参数的名称。看示例。
>>>#通过参数对应的整数来确定位置
>>>{0}今年{1}岁了。.format(妈妈,76)
'妈妈今年76岁了。'
>>>#通过关键字参数名称确定位置
>>>{who}今年{age}岁了。.format(who=妈妈,age=76)
'妈妈今年76岁了。'
>>>#上面两种方法混用
>>>{who}今年{0}岁了。.format(76,who=妈妈)
'妈妈今年76岁了。
字段名还可以使用集合数据类型------比如,列表list、字典dict。在这样的情况下,我们可以包含一个索引(不是一个分片)来标识特定的数据项,看示例:
>>>#列表索引来确定数据项
>>> familylist = [妈妈,76]
>>>{0[0]}今年{0[1]}岁了。.format(familylist)
'妈妈今年76岁了。'
>>>#词典关键字确定数据项
>>> familydict = dict(who=妈妈,age=76)
>>>{0[who]}今年{0[age]}岁了。.format(familydict)
'妈妈今年76岁了。'
总而言之,通过字段名语法,可以引用传递给str.format()方法的位置参数与关键字参数。如果参数是集合数据类型,比如列表或字典,或参数还包含一些属性,那么可以使用中括号“[]”或句点.表示法存取所需的部分。看下图
带注释的字段名实例
值得注意的是,从python3.1开始,忽略字段名也被认为是合法的,python会自动处理(使用从0开始的数值),比如:
>>> {} {} {}.format(python,can,count)
'python can count'
二、转换格式符
这里只有三个转换符号,用!开头。!r对应 repr(),也就是强制使用表象形式;!s对应 str(),也就是强制使用字符串形式; !a对应ascii(),用于强制使用表象形式,但仅限于ascii字符。看示例:
表象形式输出与打印输出的区别
>>>#python的表象形式输出
>>> import decimal
>>>decimal.decimal(3.14159265)
decimal('3.14159265')
>>>#python的打印形式输出,更关注读者感兴趣的东西
>>>print(decimal.decimal(3.14159265))
3.14159265
四种准换格式符的对比示例
>>> import decimal
>>>{0}-{0!s}-{0!r}-{0!a}.format(decimal.decimal(3.14159265))
3.14159265-3.14159265-decimal('3.14159265')-decimal('3.14159265')
三、格式化规约
整数、浮点数以及字符串的默认格式通常都足以满足要求,但是如果需要实施更精确的控制,我们就可以通过格式规约很容易地实现。为了更加易于掌握详细信息,我们分别讲述格式化字符串、整数和浮点数,先看下图的通用语法。
格式化规约的通常形式
字符串格式规约
对于字符串而言,我们可以控制的包括填充字符、字段内对齐以及字段宽度的最小值与最大值。
字符换格式规约是使用冒号(:)引入的,其后跟随可选的字符对--------一个填充字符(可以没有)与一个对齐字符(用于右对齐),之后跟随的是可选的最小宽度(整数),如果需要指定最大宽度,就在其后使用句点,句点后跟随一个整数值。注意:如果我们指定一个填充字符,就必须同时指定对齐字符。看示例。
>>> s = 字符串格式化
>>>{0}.format(s)#默认格式化
'字符串格式化'
>>>{0:30}.format(s)#最小宽度30
'字符串格式化 '
>>>{0:>30}.format(s)#最小宽度30,右对齐
' 字符串格式化'
>>>{0:^30}.format(s)#最小宽度30,居中对齐
' 字符串格式化 '
>>>{0:-^30}.format(s)#最小宽度30,居中对齐,'-'填充
'------------字符串格式化------------'
>>>{0:.
'字符串格式化........................'
>>>{0:.5}.format(s)#最大宽度5
'字符串格式'
>>> maxwidth = 4
>>>{0}.format(s[:maxwidth])#采用字符串分片方式动态控制输出格式
'字符串格'
>>>{0:.{1}}.format(s,maxwidth)#采用内部替换字段方式动态控制输出格式
'字符串格'
请大家注意以上最后两个示例,我们可以通过使用标准的字符串分片和使用内部替换字段两种方式动态控制输出格式。
整数格式规约
对于整数,通过格式规约,可以控制填充字符、字段内对齐、符号、最小字段宽度、基数等。
整数格式规约以冒号开始,其后可以跟随一个可选的字符对----------一个填充字符(可以没有)与一个对齐字符(用于右对齐,=用于在符号与数字之间进行。填充),之后跟随的是可选的符号字符,+表示必须输出符号,-表示只输出负数符号,空格表示为正数输出空格、为负数输出符号-。在之后跟随的是可选的最小宽度整数值--------其前可以使用字符#引导,以便获取某种基数进制为前缀的输出(对二进制、八进制、十六进制数值),也可以以0引导,以便在对齐时使用0填充。如果希望输出其他进制数据,而非十进制数,就必须添加一个类型字符--------b用于表示二进制,o用于表示八进制,x用于表示小写十六进制,x用于表示大写十六进制,为了完整性,也可以用d表示十进制整数。此外,还有两个其他类型字符:c,表示输出整数对应的unicode字符;n,表示以场所敏感的方式输出数字。
字很多,但是看懂了比较容易帮助理解,下面看代码示例。
>>>#填充示例
>>>{0:0=12}.format(1234567)#用0填充,最小宽度12
'000001234567'
>>>{0:0=12}.format(-1234567)#用0填充,最小宽度12,数值为负数
'-00001234567'
>>>{0:012}.format(1234567)#用0填充,最小宽度12
'000001234567'
>>>{0:a=12}.format(1234567)#用a填充,最小宽度12
'aaaaa1234567'
>>>#对齐示例
>>>{0:*
'1234567********'
>>>{0:*>15}.format(1234567)#用*填充,最小宽度15,右对齐
'********1234567'
>>>{0:*^15}.format(1234567)#用*填充,最小宽度15,居中对齐
'****1234567****'
>>>{0:*^15}.format(-1234567)#用*填充,最小宽度15,居中对齐,数值为负
'***-1234567****'
>>>#符号字符示例
>>>[{0:}][{1:}].format(7654321,-1234567)#正号用空格,负号用-号
'[7654321][-1234567]'
>>> [{0: }][{1: }].format(7654321,-1234567)#正号用空格,负号用-号
'[ 7654321][-1234567]'
>>>[{0:+}][{1:+}].format(7654321,-1234567)#强制用符号,正号用+号,负号用-号
'[+7654321][-1234567]'
>>>[{0:-}][{1:-}].format(7654321,-1234567)#必须用符号才用符号,正号不用符号,负号用-号
'[7654321][-1234567]'
>>>#类型字符示例
>>>[{0:b}][{0:o}][{0:x}][{0:x}].format(12345678)#b是二进制,o是八进制
'[101111000110000101001110][57060516][bc614e][bc614e]'
>>> [{0:#b}] [{0:#o}] [{0:#x}] [{0:#x}].format(12345678)#x是小写十六进制,x是大写十六进制
'[0b101111000110000101001110] [0o57060516] [0xbc614e] [0xbc614e]'
>>>#,号分组示例
>>> [{0:,}] [{0:*>13,}].format(123456789)
'[123,456,789] [**123,456,789]'
浮点数格式规约
对于浮点数,通过格式规约,可以控制填充字符、字段对齐、符号、最小字段宽度、十进制小数点后的数字个数,以及是以标准形式、指数形式还是以百分数的形式输出数字。
用于浮点数的格式规约与用于整数的格式规约是一样的,只是在结尾处有两个差别。在可选的最小宽度后面,通过写一个句点并在其后跟随一个整数,我们可以指定在小数点后跟随的数字个数。我们也可以在结尾处添加一个类型字符:e表示使用小写字母e的指数形式,e表示使用大写字母e的指数形式,f表示标准的浮点形式,g表示“通常”格式——这与f的作用是相同的,除非数字特别大(在这种情况下与e的作用相同——以及几乎与g等同的g,但总是使用f或e)。另一个可以使用的是%——这会导致数字扩大100倍,产生的数字结果使用f并附加了一个%字符的格式输出。请看示例。
>>>#填充示例
>>>{0:0=18}.format(1234567.76543)#用0填充,最小宽度18
'000001234567.76543'
>>>#对齐示例
>>>{0:*^18}.format(1234567.76543)#用*填充,最小宽度18,居中对齐
'**1234567.76543***'
>>>#符号字符示例
>>>[{0:+}][{1:+}].format(1234567.76543,-1234567.76543)#强制用符号,正号用+号,负号用-号
'[+1234567.76543][-1234567.76543]'
>>>
>>>#,号分组示例
>>> [{0:,}] [{0:*>18,}].format(1234567.76543)
'[1,234,567.76543] [***1,234,567.76543]'
>>>#指数形式和标准形式示例
>>> [{0:12.2e}] [{0:12.2f}].format(1234567.76543)#最小宽度12,小数点后2位,第一个用指数e形式表示
'[ 1.23e+06] [ 1234567.77]'
>>> [{0:*>12.2e}] [{0:*>12.2f}].format(1234567.76543)#最小宽度12,小数点后2位,第一个用指数e形式表示,用*填充
'[****1.23e+06] [**1234567.77]'
>>> [{0:*>+12.2e}] [{1:*>+12.2f}].format(1234567.76543,-1234567.76543)#最小宽度12,小数点后2位,第一个用指数e形式表示,用*填充,强制使用符号
'[***+1.23e+06] [*-1234567.77]'
四、几点细节
类内格式化重写
类和类型可以定义一个__format__()方法来控制怎样格式化自己。它会接受一个格式化指示符作为参数,根据format前的字符串格式来定制不同的显示,如: ’{:xxxx}’ 此时xxxx会作为参数传入__format__函数中:
class move(object):
def __format__(self, format):
if (format == 'jump'):
return i'm afraid i can't do that.
return 'move'
'{:jump}'.format(move())
输出结果:i'm afraid i can't do that.
还有一个内置的format()方法可以用来格式化一个值。它会调用类型的__format__()方法,并将格式化指示符作为参数传进去。
>>> format(75.6564, '.2f')
'75.66'
时间日期的特例
>>> from datetime import datetime
>>> '{:%y-%m-%d %h:%m}'.format(datetime(2018, 2, 3, 4, 5))
'2018-02-03 04:05'
中文字符无法对齐问题
中文字符在字符占用上相当于两个英文字符,但是字体设计上,一般一个中文字符的宽度不会等于两个英文字符的宽度,所以打印出来的效果有偏差。
c = [
'爱',
'爱爱',
'爱爱爱',
'爱爱爱爱',
'爱爱爱爱爱',
'爱爱爱爱爱爱',
'爱爱爱爱爱爱爱'
]
print('----正常字符串格式化:----')
for x in range(len(c)):
print('|%20s|' % c[x])
效果如下:
打印出的字符有偏差,无法对齐
但是等宽字符一个中文字体的宽度刚好等于两个英文�...