前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字符串格式化输出

字符串格式化输出

作者头像
老齐
发布2021-07-05 15:33:19
9580
发布2021-07-05 15:33:19
举报
文章被收录于专栏:老齐教室
以下内容是正在编写的一本书的节选,算是提前剧透。

输出的字符串是给人看的,于是就需要有各种样式,弄得好看一些——子曰:“已矣乎!吾未见好德如好色者也。”——表面功夫必须要做。

1. 字符串的 format() 方法

根据一贯提倡的自学方法,应该先看看帮助文档,执行 help(str.format) 会看到如下内容:

代码语言:javascript
复制
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 负责收集“关键词参数”——不需要对这句话进行深究,后续内容中会详解。例如:

代码语言:javascript
复制
>>> "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):

代码语言:javascript
复制
>>> "I like {subject} and {lang}".format(lang="python", subject="physics")
'I like physics and python'

图4-2-11 format() 的关键词参数

★自学建议 由于多种原因,比如历史沿革、为了直观形象,甚至于自己才疏学浅,读者在本书中可能会看到一些不是太严谨的用语,比如上面介绍参数的时候,使用了“传入”——给 format() “传入”参数——并且打了引号,这类术语严格来讲对 Python 不适合,但是看起来比较形象,特别是便于初学者理解。并且,在此提醒读者,随着学习的深入,你可能会觉得入门阶段所学的东西不那么严谨。这并非都是作者的错误,有时候为了让初学者更容易理解,并且还要考虑到可读性,不得不在“科学严谨性”与“简单明了”之间做取舍。但是,这并不意味着读者的理解也总停留在“科普”的水平上,而是要不断进阶,成为专业者,并能意识到入门阶段的理解仅仅是入门。

下面以位置参数为例,对格式化输出做更深入探讨。

首先,在模板中,可以根据位置参数的顺序编号,将该参数放置在任何位置,即占位符中的数字并非一定从左向右排序,例如:

代码语言:javascript
复制
>>> "I like {1} and {0}. {0} is a programming language".format("python", "physics")
'I like physics and python. python is a programming language' 

“格式化输出”的格式不仅仅是“位置”,还包含“样式”。使用 format() 方法可以实现多种输出“样式”。

代码语言:javascript
复制
>>> "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} 表示字符串在该位置的对齐方式是居中。

除了规定字符串的对齐方式之外,还可以限制显示的字符个数。

代码语言:javascript
复制
>>> "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() 的参数,不仅是字符串,还可以是数字(包括整数和浮点数),而且也能有各种花样。

代码语言:javascript
复制
>>> "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} 表示该位置放第二个参数,且为浮点数,此处浮点数的小数位数是默认的。
代码语言:javascript
复制
>>> "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位,并且自动采用四舍五入方式对参数中小数进行位数截取操作,默认也是右对齐。
代码语言:javascript
复制
>>> "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 填充。

如果使用关键词参数,输出格式控制方法同上,例如:

代码语言:javascript
复制
>>> "{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() 的参数中混合使用关键词参数和位置参数呢?可以,但必须将位置参数放在前面。

代码语言:javascript
复制
>>> '{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} 中冒号右侧的写法,其通用的形式是:

代码语言:javascript
复制
:[[<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

十六进制整数

%

百分数

代码语言:javascript
复制
# 演示 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() 实现多样化的格式化输出,甚至让人眼花缭乱,不过要想熟练掌握,还需要读者多多练习,绝非读了本书寥寥数语即可获得神功。

2. f-字符串

自 Python 3.6(此前版本无此功能,请读者特别注意),在格式化输出上推出了格式化字符串字面量(formatted string literal),简称f-字符串(f-string)。其基本语法格式为:fF 后面紧跟一个字符串(可以用单引号、双引号、三引号),所得到的的对象还是一个字符串,如下述操作:

代码语言:javascript
复制
>>> s = f'python book'
>>> type(s)
<class 'str'>
>>> p = F"人面桃花相映红"
>>> type(p)
<class 'str'>
>>> p
'人面桃花相映红'

如果仅仅如此,则f-字符串简直是画蛇添足,它的魔幻之处在于可以在其中加入 { } ,而 { } 里面则可以容纳变量,从而 f-字符串变成了一个表达式。

代码语言:javascript
复制
>>> f'poem is {p}'
'poem is 人面桃花相映红'

甚至于直接在 { } 中嵌入其他表达式——不仅仅是变量。

代码语言:javascript
复制
>>> 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() 方法式的模板书写样式即可——前面苦学后,现在就轻松了。

代码语言:javascript
复制
>>> alpha = 30
>>> f"the sine of alpha is {math.sin(alpha*math.pi/180):10.3f}"
'the sine of alpha is      0.500'

所以,此处不再赘述,读者可以参照前面的内容进行练习。

除了本节重点介绍的这两种格式化输出方法之外,在 Python 历史上还曾使用 % 实现格式化输出,例如:

代码语言:javascript
复制
>>> "My name is %s" % "laoqi"
'My name is laoqi'

只是这种形式在现在的 Python 编程中已经很少使用,读者见到时亦不必大惊小怪。


★本书是对以往我写的 Python 基础内容的全新升级,且强调读者自学。我会在本微信公众号持续发布书稿的节选内容。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 字符串的 format() 方法
  • 2. f-字符串
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档