输出的字符串是给人看的,于是就需要有各种样式,弄得好看一些——子曰:“已矣乎!吾未见好德如好色者也。”——表面功夫必须要做。
format()
方法根据一贯提倡的自学方法,应该先看看帮助文档,执行 help(str.format)
会看到如下内容:
format(...)
S.format(*args, **kwargs) -> str
Return a formatted version of S, using substitutions from args and kwargs.
The substitutions are identified by braces ('{' and '}').
读者在这里看到了 format()
参数中有此前未曾出现的符号 *args, **kwargs
,其中 *args
负责收集“位置参数”,**kwargs
负责收集“关键词参数”——不需要对这句话进行深究,后续内容中会详解。例如:
>>> "I like {0} and {1}".format("python", "physics")
'I like python and physics'
在交互模式中,输入了字符串 "I like {0} and {1}"
,其中用 {0}
和 {1}
占据了两个位置,称之为占位符——这种说法有点古老了,比较新潮的可以说成“替代域”(replacement field)——不论叫什么,对应的位置要被 format()
的参数引用的对象替代。
对于 format("python", "physics")
的参数所引用的两个字符串,按照4.2.4节的索引思想,也给它们“编号”。第一个字符串应该编号为 0
——这是 Python 的惯例,从“0”开始计数,则这个位置的字符串 "python"
对应于占位符 {0}
;同理,第二个字符串 "physics"
对应于占位符 {1}
。像这样,根据位置给方法“传入”的参数称为位置参数(positional argument)。占位符中的数字 0、1
分别对应于位置参数的顺序“编号”(如图4-2-10所示)。
图4-2-10 format() 的位置参数
显然,如果更换 format()
中的参数,所得到的输出结果会有不同,但基本结构一样,都符合 "I like {0} and {1}"
所规定的样式,因此这个字符串被称为模板(template)——可以直观地理解为:用模板建立了输出格式。
下面的操作,是用另外一种方式给 format()
“传入”参数(如图4-2-11所示),即为每个将要“传入”的字符串命名一个“变量”——称为关键词参数(keyword argument):
>>> "I like {subject} and {lang}".format(lang="python", subject="physics")
'I like physics and python'
图4-2-11 format() 的关键词参数
★自学建议 由于多种原因,比如历史沿革、为了直观形象,甚至于自己才疏学浅,读者在本书中可能会看到一些不是太严谨的用语,比如上面介绍参数的时候,使用了“传入”——给
format()
“传入”参数——并且打了引号,这类术语严格来讲对 Python 不适合,但是看起来比较形象,特别是便于初学者理解。并且,在此提醒读者,随着学习的深入,你可能会觉得入门阶段所学的东西不那么严谨。这并非都是作者的错误,有时候为了让初学者更容易理解,并且还要考虑到可读性,不得不在“科学严谨性”与“简单明了”之间做取舍。但是,这并不意味着读者的理解也总停留在“科普”的水平上,而是要不断进阶,成为专业者,并能意识到入门阶段的理解仅仅是入门。 ”
下面以位置参数为例,对格式化输出做更深入探讨。
首先,在模板中,可以根据位置参数的顺序编号,将该参数放置在任何位置,即占位符中的数字并非一定从左向右排序,例如:
>>> "I like {1} and {0}. {0} is a programming language".format("python", "physics")
'I like physics and python. python is a programming language'
“格式化输出”的格式不仅仅是“位置”,还包含“样式”。使用 format()
方法可以实现多种输出“样式”。
>>> "I like {0:10} and {1:>15}".format("python", "physics")
'I like python and physics'
>>> "I like {0:^10} and {1:^15}".format("python", "physics")
'I like python and physics '
上述代码中的格式含义如下:
{0:10}
表示该位置的宽度是10个字符,并且放在这个位置的字符串是左对齐;{1:>15}
表示该位置的宽度是15个字符,并且放在这个位置的字符串是右对齐;{0:^10}
和 {1:^15}
表示字符串在该位置的对齐方式是居中。除了规定字符串的对齐方式之外,还可以限制显示的字符个数。
>>> "I like {0:.2} and {1:^15.3}".format("python", "physics")
'I like py and phy '
{0:.2}
中的 .2
表示对于传入的字符串,截取前两个字符。需要注意的是,在冒号 :
后面和句点 .
前面,没有任何数字,意思是该位置的宽度自动适应即将放到该位置的字符串。{1:^15.3}
中的 15.3
表示该位置的宽度是15个字符,但即将放入该位置的字符串应该仅仅有3个字符,也就是要从传入的字符串 "physics"
中截取前3个字符,即为 "phy"
。format()
的参数,不仅是字符串,还可以是数字(包括整数和浮点数),而且也能有各种花样。
>>> "She is {0:d} years old and {1:f}m in height.".format(28, 1.68)
'She is 28 years old and 1.680000m in height.'
{0:d}
表示在该位置放第一个参数,且为整数;{1:f}
表示该位置放第二个参数,且为浮点数,此处浮点数的小数位数是默认的。>>> "She is {0:4d} years old and {1:.1f}m in height.".format(28, 1.68)
'She is 28 years old and 1.7m in height.'
{0:4d}
表示此位置的宽度是4个字符,并且在其中应该放置整数。默认状态下,整数是右对齐;{1:.1f}
表示该位置的浮点数的小数位数为1位,并且自动采用四舍五入方式对参数中小数进行位数截取操作,默认也是右对齐。>>> "She is {0:04d} years old and {1:06.1f}m in height.".format(28, 1.68)
'She is 0028 years old and 0001.7m in height.'
{0:04d}
和 {1:06.1f}
则表示在该位置的空位,用 0
填充。
如果使用关键词参数,输出格式控制方法同上,例如:
>>> "{name:^10} is {age:04d} years old and is a {job:>20}.".format(name='Dynami', job='painter', age=28)
' Dynami is 0028 years old and is a painter.'
对此的更多联系,请读者自行仿照前述内容实施。
是否可以在 format()
的参数中混合使用关键词参数和位置参数呢?可以,但必须将位置参数放在前面。
>>> '{0}--{1}--{name}'.format(a, b, name=c)
'python--book--laoqi'
# “偷懒”的写法
>>> '{}--{}--{name}'.format(a, b, name=c)
'python--book--laoqi'
# 这样写就报错了
>>> '{}--{}--{name}'.format(name=c, a, b)
File "<stdin>", line 1
'{}--{}--{name}'.format(name=c, a, b)
^
SyntaxError: positional argument follows keyword argument
以上以几个简单的示例说明了利用字符串的 format()
方法实现格式化输出的基本方式,从中读者也体会到,对输出格式的制定是比较复杂多样的,即 {age:04d}
中冒号右侧的写法,其通用的形式是:
:[[<fill>]<align>][<sign>][#][0][<width>][<group>][.<prec>][<type>]
表4-2-3中对其各个组成部分给予详细说明,请读者参考,并作为备查资料。
表4-2-4 格式组成说明
组成 | 说明 |
---|---|
: | 与前面的索引或关键词分割 |
<fill> | 在 <width> 不空时生效,并与 <align> 配合使用。指定未被对象占据的位置填充字符。 |
<align> | 在 <width> 不空时生效。控制对象的显示位置:< 左对齐;> 右对齐;^ 居中。 |
<sign> | 当输出数字时,用于控制数字前是否符号。若用 +,不论输出正数还是负数,均在输出结果中有符号;若用 -,仅在输出负数时有符号,正数则无。如演示1。 |
# | 用于强制显示某些字符,如演示2。 |
0 | 输出对象宽度小于位置宽度,空位填充 0 。 |
<width> | 指定该位置的最小宽度(以字符为单位)。如果参数长度大于此值,则此约束失效。 |
<group> | 数字分隔符,可以使用 , 和 _ ,如演示3。 |
.<prec> | 声明浮点数的小数位数或者字符串的最大长度。 |
<type> | 指定格式化输出的对象类型。常用类型如表4-2-4所示。如演示4。 |
表4-2-4 输出类型
类型符号 | 说明 |
---|---|
b | 二进制整数 |
c | 单个字符 |
d | 十进制整数 |
e 或 E | 科学计数法 |
f 或 F | 浮点数 |
g 或 G | 浮点数或科学计数法 |
o | 八进制整数 |
s | 字符串 |
x 或 X | 十六进制整数 |
% | 百分数 |
# 演示 1
>>> '{0:+6d}'.format(314)
' +314'
>>> '{0:+6d}'.format(-314)
' -314'
>>> '{0:-6d}'.format(-314)
' -314'
>>> '{0:-6d}'.format(314)
' 314'
# 演示 2
>>> '{0:.0f}'.format(3.14) # 输出的浮点数没有小数
'3'
>>> '{0:#.0f}'.format(3.14) # 输出的浮点数没有小数,强制输出小数点
'3.'
# 演示 3
>>> '{0:,}'.format(31415926)
'31,415,926'
>>> '{0:_}'.format(31415926)
'31_415_926'
# 演示 4
>>> '{0:b}'.format(255)
'11111111'
>>> '{0:o}'.format(255)
'377'
>>> '{0:x}'.format(255)
'ff'
>>> '{0:f}'.format(255)
'255.000000'
>>> '{0:%}'.format(0.314)
'31.400000%'
依照通用格式,将表4-2-4以及相关设置综合运用,能够让 format()
实现多样化的格式化输出,甚至让人眼花缭乱,不过要想熟练掌握,还需要读者多多练习,绝非读了本书寥寥数语即可获得神功。
自 Python 3.6(此前版本无此功能,请读者特别注意),在格式化输出上推出了格式化字符串字面量(formatted string literal),简称f-字符串(f-string)。其基本语法格式为:f
或 F
后面紧跟一个字符串(可以用单引号、双引号、三引号),所得到的的对象还是一个字符串,如下述操作:
>>> s = f'python book'
>>> type(s)
<class 'str'>
>>> p = F"人面桃花相映红"
>>> type(p)
<class 'str'>
>>> p
'人面桃花相映红'
如果仅仅如此,则f-字符串简直是画蛇添足,它的魔幻之处在于可以在其中加入 { }
,而 { }
里面则可以容纳变量,从而 f-字符串变成了一个表达式。
>>> f'poem is {p}'
'poem is 人面桃花相映红'
甚至于直接在 { }
中嵌入其他表达式——不仅仅是变量。
>>> f'the book is about {s[:6]}'
'the book is about python'
>>> f'诗句的字数是{len(p)}'
'诗句的字数是7'
>>> import math
>>> alpha = 60
>>> f"the sine of alpha is {math.sin(alpha*math.pi/180)}"
'the sine of alpha is 0.8660254037844386'
>>> alpha = 90
>>> f"the sine of alpha is {math.sin(alpha*math.pi/180)}"
'the sine of alpha is 1.0'
>>> z = 3 + 5j
>>> print(f'value = {z}, real = {z.real}, imag = {z.imag}')
value = (3+5j), real = 3.0, imag = 5.0
f-字符串也同样能按照规定的模板样式输出,并且,照搬前面介绍 format()
方法式的模板书写样式即可——前面苦学后,现在就轻松了。
>>> alpha = 30
>>> f"the sine of alpha is {math.sin(alpha*math.pi/180):10.3f}"
'the sine of alpha is 0.500'
所以,此处不再赘述,读者可以参照前面的内容进行练习。
除了本节重点介绍的这两种格式化输出方法之外,在 Python 历史上还曾使用 %
实现格式化输出,例如:
>>> "My name is %s" % "laoqi"
'My name is laoqi'
只是这种形式在现在的 Python 编程中已经很少使用,读者见到时亦不必大惊小怪。
★本书是对以往我写的 Python 基础内容的全新升级,且强调读者自学。我会在本微信公众号持续发布书稿的节选内容。 ”