读完这一篇,字符串格式化界的“白富美”(f-strings)抱回家!
f-strings
从Python 3.6开始,新引入了一种字符串格式化方法,称为“格式化字符串常量”(formatted string literal),简称f-strings。相比于%、str.format、string.Template这些字符串格式化方法,f-strings在功能上一点不逊色,性能更优,而且更易读、更简洁,也不易出错。如果你使用的是Python3.6以上的版本,建议你使用f-strings来格式化字符串。
f-strings是以f或F打头的字符串,形如f'Ilove {name}'、F'I am {name} and I am {age} years old.'。请注意,在f(或F)与引号之间不要有空格,否则会引起语法错误。另外,对于f后面字符串的引号,你可以使用单引号、双引号或三引号,但是要配对使用,不可出现交叉,相同引号不能嵌套,这与创建普通字符串时对引号的使用要求是一样的。f-strings提供了一种把表达式嵌入字符串中的方法,而且语法相当简洁,我们只需要把表达式直接放入一对花括号中就行了。请注意,f-strings中可以有多个花括号,但这些花括号必须成对出现,不允许有单个左花括号或右花括号存在。程序运行时会计算表达式的值,并使用结果值替换表达式,最终形成一个完整的字符串。这里所说的“表达式”可以是任意表达式,包括变量、函数、各种运算表达式、条件表达式,以及lambda表达式等。
>>> name = 'Lily'
# 使用单引号
>>> f'I love {name}'
'I love Lily'
# f和'之间有空格
>>> f 'I love {name}'
SyntaxError: invalid syntax
# 使用双引号
>>> f"I love {name}"
'I love Lily'
# 使用三引号
>>> f'''I love {name}'''
'I love Lily'
>>> f'''I love {name},
and Jack loves {name},too.'''
'I love Lily,\nand Jack loves Lily,too.'
# 调用字符串的upper()函数
# 把名字转换为大写
>>> f'I love {name.upper()}'
'I love LILY'
>>> f'The area of the circle is{3.14*2*2}'
'The area of the circle is 12.56'
当f-strings引用字典中的值时,一定要特别注意引号使用的问题,相同引号不要进行嵌套。
# 单引号出现了嵌套
>>> dic = {'name':'Lily','age':18}
>>> f'I am {dic['name']},and I am{dic['age']} years old.'
SyntaxError: invalid syntax
>>> f'I am{dic["name"]},and I am {dic["age"]} years old.'
'I am Lily,and I am 18 years old.'
如果字符串本身就包含花括号,要求原样保留在最终结果中,为此需要在f-strings中使用两个花括号进行转义。连续两个左花括号代表结果字符串中一个左花括号,连续两个右括号代表结果字符串中的一个右括号。
>>> f'{{{"lily".upper()} }}'
'{ LILY }'
>>>f'{{{"lily".upper()}}}'
'{LILY}'
# 连续两个花括号之间不能有空格
>>> f'{ {{"lily".upper()} }}'
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
f'{ { {"lily".upper()} }}'
TypeError: unhashable type: 'set'
除了表达式之外,花括号中还可以有格式说明符,如下:
>>> f'π的值是{pi:.2f}'
'π的值是3.14'
>>> f'{75:+#010x}'
'+0x000004b'
f-strings的完整形式如下:

注:上面中的[]表示是可选的。
- 表达式(expression):对于表达式,我们应该注意如下几点:
- f-strings要求花括号中必须有表达式。 
- f-strings可以包含任意表达式,它可以是变量、常量、各种运算表达式、条件表达式、函数等。当然,f-strings中的表达式可以是lambda表达式,但lambda表达式中的冒号(:)容易被f-strings误认为是表达式和格式说明符之间的冒号分隔符。为了避免出现这个问题,使用lambda表达式时,需要先把它放入到一个圆括号里面,然后再放入花括号中,例如: 
>>> import math
>>> r = 3
>>> f'半径为{r}的圆的面积是:{(lambda r:math.pi*r*r)(r):.2f}'
'半径为3的圆的面积是:28.27'
- 表达式中不应该包含:或!两个符号,但这两个符号允许出现在表达式所包含的字符串之中。 
- 表达式中也不允许出现反斜杠(\),也就是说,我们无法在表达式中使用转义字符进行转义操作(但转义字符可以用在text之中进行转义)。 
- 以#打头的文本不允许直接出现在表达式中。但允许出现在表达式所包含的字符串之中。 
- 表达式中允许出现!=运算符 
- 类型转换标志:类型转换标志和str.format()的类型转换标志一样,有三个可能的取值,分别是!s、!r、!a。设置为!s表示调用str()对表达式进行转换(默认方式);!r表示调用repr()对表达式进行转换;!a表示调用ascii()对表达式进行转换。这些转换发生在调用format()函数使用格式说明符对表达式做格式化之前。
- 格式说明符(format specifier):f-strings的格式说明符和str.format()的格式说明符是一样的。给出了格式化说明符之后,这些说明符会被作为参数传入__format__函数对表达式的值进行格式化,若不指定格式说明符,则向__format__函数传入空字符串。有关格式说明符的内容,我们在前面讲解str.format()时已经讲过了,这里就不再赘述了。
请注意:格式化说明符中可以嵌套使用表达式。f-strings执行时会先计算这些嵌套表达式,得到完整的格式化说明符,然后再使用格式化说明符格式化外层表达式。例如:
>>> pi= 3.1415926
>>>width = 10
>>>precision = 3
>>> f'π的值是:{pi:{width}.{precision}f}'
'π的值是: 3.142'
下面举一些使用格式化说明符的例子:
>>>import math
>>>math.pi
3.141592653589793
# *指填充符号
# ^居中对齐
# +显示符号
# 10是替换字段宽度
# .3是精度
# f是浮点数
>>>f'The value of PI is {math.pi:*^+10.3f}'
'The value of PIis **+3.142**'
# =:内容右对齐,且只对数字类型有效。
# 若有符号,将其放在填充字符左侧,
# 形成“符号+填充字符+数字”的格式
>>>f'The value of PI is {math.pi:*=+10.3f}'
'The value of PIis +****3.142'
# #表示显示二进制、八进制、十六进制前缀
# 0表示空白处填充0,相当于把fill设置为0且使用=对齐方式。
# 10替换字段宽度
# X表示把十进制整数转换成十六进制数
>>>f'{55:+#010X}'
'+0X0000037'
# ,为千分位符号
>>>digit = 45724561
>>>f'The digit is {digit:+015,d}'
'The digit is+00,045,724,561'
友情提示:有关格式化说明符的详细内容,请参考公众号里介绍str.format()的文章,那里有非常详细的讲解。
“人生苦短,要学Python”
在f-strings中,f和r(或R)可以结合使用,且先后顺序任意(fr或rf),用以创建原生f-strings。上面讲解中,我们提到在f-strings的花括号外面的字符串中可以使用转义字符进行转义处理。但,若f-strings前面使用了fr或rf作为前缀,则这些转义字符会被当成普通的字符,失去转义功能,这在构建正则表达式时会非常有用。
>>> print(f'I love\n{"Lily"}')
I love
Lily
# 原生f-strings
# 转义字符被当成普通字符
# 失去转义功能
>>> print(fr'I love\n{"Lily"}')
I love\n Lily
另外,相邻的f-strings和普通字符串会自动连接在一起。两个相邻的普通字符串会在编译时连接起来,而f-strings只有运行时才进行连接。
>>> name1 = 'Lily'
>>> name2 = 'Python'
>>> 'I ''love'f'{name1}'f'{"and":^5}'f'{name2}'
'I love Lily and Python'
# 各个字符串之间可以有任意多个空格
# 连接时这些空格会被忽略
>>> 'I ' 'love ' f'{name1}' f'{"and":^5}' f'{name2}'
'I love Lily and Python'
尽管f-strings支持把整个表达式写入{}之中,但有时这样做会引起困扰,比如:
>>> f'{{1:2,3:4}}'
'{1:2,3:4}'
>>> f'{ {1:2,3:4} }'
'{1: 2, 3: 4}'
在第一个f-strings例子中,外层{}与内层{}之间没有空格,所以里面的{{和}}是用来做转义,分别表示一个左花括号({)和一个右花括号(}),这从结果字符串中可以看到这一点。
而在第二个f-strings例子中,外层{}与内层{}之间有空格,内层{}表示的是一个字典,外层{}表示对内层字典表达式求值,结果是字典本身。我们可以把第二个f-strings例子改写为:
>>> dic = {1:2,3:4}
>>> f'{dic}'
'{1: 2, 3: 4}'
有些表达式直接写在f-strings中,容易产生令人困惑的结果。对于这样的表达式,建议大家不要把整个表达式放入f-strings之中,而像上面改写的那样分开写,这可以让f-strings变得更加清晰可读。
值得注意的是,f-strings也可以用来格式化日期时间。不同于普通字符串,日期时间有自己的一套格式化方法。使用f-strings格式化日期时间时,前面提到的格式化说明符将不再起作用,必须使用日期时间特有的格式化符号,具体有哪些格式化符号,请参照下表。
| 格式化符号 | 含义 | 举例 | 
| %a | 星期几(本地缩写) | Sun, Mon, …, Sat | 
| %A | 星期几(本地全名) | Sunday, Monday, …, Saturday | 
| %w | 星期几(以十进制数0-6表示,0代表星期天,6代表星期六) | 0, 1, …, 6 | 
| %u | 星期几(ISO 8601标准,以十进制数表示,1代表星期一) | 1, 2, …, 7 | 
| %d | 日(以两位十进制数表示,不足两位用0补齐) | 01, 02, …, 31 | 
| %b | 月份(本地缩写) | Jan, Feb, …, Dec | 
| %B | 月份(本地全名) | January, February, …, December | 
| %m | 月份(以两位十进制数表示,不足两位用0补齐) | 01, 02, …, 12 | 
| %y | 年(年份后两位数,以两位十进制数表示,不足两位用0补齐) | 00, 01, …, 99 | 
| %Y | 年(以四位十进制数表示,不足四位用0补齐) | 0001, 0002, …, 2013, 2014, …, 9998, 9999 | 
| %G | 年(ISO8601标准,以四位十进制数表示,不足四位用0补齐,包含ISO大部分周(%V)) | 0001, 0002, …, 2013, 2014, …, 9998, 9999 | 
| %H | 时(24时制,以两位十进制数表示,不足两位用0补齐) | 00, 01, …, 23 | 
| %I | 时(12时制,以两位十进制数表示,不足两位用0补齐) | 01, 02, …, 12 | 
| %p | 上午/下午的本地表示 | AM, PM | 
| %M | 分(以两位十进制数表示,不足两位用0补齐) | 00, 01, …, 59 | 
| %S | 秒(以两位十进制数表示,不足两位用0补齐) | 00, 01, …, 59 | 
| %f | 微秒(以六位十进制数表示,不足六位用0补齐) | 000000, 000001, …, 999999 | 
| %z | UTC偏移(格式为±HHMM[SS[.ffffff]],若未指定时区,则返回空字符串) | +0000, -0400, +1030, +063415, -030712.345216 | 
| %Z | 时区名(若未指定时区,则返回空字符串) | UTC, EST, CST | 
| %j | 一年中的第几天(以三位十进制数表示,不足三位用0补齐) | 001, 002, …, 366 | 
| %U | 一年中的第几周(以星期天作为星期的第一天,以两位十进制数表示,不足两位用0补齐,全年第一个星期天之前的那个周称为第0周) | 00, 01, …, 53 | 
| %W | 一年中的第几周(以星期一作为星期的第一天,以两位十进制数表示,不足两位用0补齐,全年第一个星期一之前的那个周称为第0周) | 00, 01, …, 53 | 
| %V | 一年中的第几周(ISO8601标准,以星期一作为星期的第一天,以两位十进制数表示,不足两位用0补齐,包含1月4日的那一周为第01周) | 00, 01, …, 53 | 
| %c | 适合本地的日期时间表示 | Tue Aug 16 21:30:00 1988 (en_US); Di 16 Aug 21:30:00 1988 (de_DE) | 
| %x | 适合本地的日期表示 | 08/16/88 (None); 08/16/1988 (en_US); 16.08.1988 (de_DE) | 
| %X | 适合本地的时间表示 | 21:30:00 (en_US); 21:30:00 (de_DE) | 
| %% | 百分号 | % | 
| %T | 显示时分秒(格式hh:mm:ss) | 10:47:00 | 
| %D | 显示月日年(格式mm/dd/yy) | 01/12/19 | 
| %R | 显示时分(格式hh:mm) | 10:47 | 
| %t | 水平制表符 | |
| %n | 换行 | |
| %F | 显示年月日(格式yyyy-mm-dd) | 2019-01-12 | 
>>> import datetime
>>> dt = datetime.datetime.today()
>>> f'The time is {dt:%Y-%m-%d %a%H:%M:%S}'
'The time is 2019-01-12 Sat 10:47:00'
>>> f'The time is {dt:%F %a %T}'
'The time is 2019-01-12 Sat 10:47:00'
关注我
“人生苦短,要学Python”
读完这一篇,字符串格式化界的“白富美”(f-strings)抱回家!的更多相关文章
- Python学习之路——基础篇(1)字符串格式化
		字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存. 百分号方式 ... 
- Python_Day_5装饰器、字符串格式化、序列化、内置模块、生成器、迭代器之篇
		一.装饰器 为什么要用装饰器??? 在实际的开发环境中应遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但也适用于函数式编程,简单地说,它规定已经实现的功能代码不是允许修改的,但是可以被扩展: 封 ... 
- Python开发【第一篇】Python基础之字符串格式化
		字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存.[PEP-310 ... 
- 第二篇*2、Python字符串格式化
		1.字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 1)百分号方式 %[(name)][flags][width].[precision]typecode (nam ... 
- 第十篇 Python的字符串格式化
		字符串格式化:就是按照你的意愿做一个拼接的过程. 1. 字符串格式化的第一种方式:百分号方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存. %[ ... 
- Java 字符串格式化详解
		Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ... 
- C++字符串格式化库:CPPFormatLibrary
		这个是很久之前写的,去年总结了一下,将其单独提取出来,作为一个开源库放到了GitHub上,然而CPPFormat之类的名字都已经被抢注了,结果只好注册了一个这么蛋疼的名字:CPPFormatLibra ... 
- PHP字符串格式化特点和漏洞利用点
		转载至: https://www.anquanke.com/post/id/170850 PHP中的格式化字符串函数 在PHP中存在多个字符串格式化函数,分别是printf().sprintf().v ... 
- 【Python】更优的字符串格式化方式 -- "format"替代"%s"
		背景 前段时间看了一篇介绍Python的代码技巧的文章,建议格式化字符串时使用"format"代替使用"%",但是没有说明原因.各博客网站介绍相关用法的博客很多 ... 
随机推荐
- dos5章
			一.用set命令设置自定义变量 显示.设置或删除 cmd.exe 环境变量. SET [variable=[string]]variable 指定环境变量名.string 指定要指派给变量的一系列字符 ... 
- TP5 model层  返回的对象转数组
			打开 database.php 增加或修改参数'resultset_type' => '\think\Collection',即可连贯操作 model('user')->select()- ... 
- 基于Verilog的带FIFO输出缓冲的串口接收接口封装
			一.模块框图及基本思路 rx_module:串口接收的核心模块,详细介绍请见“基于Verilog的串口接收实验” rx2fifo_module:rx_module与rx_fifo之间的控制模块,其功能 ... 
- python学习第三次记录
			python学习第三次记录 python中常用的数据类型: 整数(int) ,字符串(str),布尔值(bool),列表(list),元组(tuple),字典(dict),集合(set). int.数 ... 
- 更改Windows更新源(解决公司内部网络无法下载语言包或更新的问题)
			打开注册表 找到HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate 将WUServer.WUStatusServe ... 
- 同步I/O、异步I/O与阻塞I/O、非阻塞I/O的区别
			一.I/O I/O (Input/Output,输入/输出)即数据的读取(接收)或写入(发送)操作. 通常用户进程中的一个完整I/O分为两阶段:用户进程空间<-->内核空间.内核空间< ... 
- Linux中(Ubuntu18.04.x/CentOS)mysql8.0.x安装/配置/部署/启动
			The MySQL Connectors and APIs are the drivers and libraries that you use to connect applications in ... 
- 软件测试_Fiddler抓包工具一
			多数资料摘抄至 https://www.cnblogs.com/miantest/p/7289694.html 一.在 macOS 下如何安装 (https://www.telerik.com/fid ... 
- zoj 1649 bfs
			Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M ... 
- pycharm汉化补丁
			将压缩包内容复制到 x:\xxx\JetBrains\PyCharm Community Edition 2019.1\lib 目录下 链接:https://pan.baidu.com/s/1TLEP ... 
