f-string: 改进的 Python 字符串格式化语法

f-strings 是 Python 3.6 引入的一种非常棒的字符串格式化方法。

相比其他格式方法,f-strings 更易读、更简洁、更少犯错,也更快。

在了解为什么以及如何使用 f-strings 之前,我们先看一下在 f-strings 之前 Python 是如何进行字符串格式化的。那是一段很艰难的日子,犹如大雪中艰难攀爬上下学路上的山坡。


【Python 中字符串格式的老式方法】

Python 3.6 之前,有两种主要方式可将 Python 表达式嵌入到常量字符串中进行格式化:% 格式化语法和 str.format() 方法。

我们来看一下这两种方法的使用方法和局限之处。

1,% 格式化语法

这是 Python 中最古老的一种格式化方法,从一开始就存在于语言规范中。你可以在 Python 官方文档中获取更多相关信息。

你需要知道,官方文档并不推荐 % 格式化方法,并给出如下理由:

这里描述的格式化操作表现出各种怪癖,会导致一些常见的错误,比如无法正确显示 tuples 和 dicts。
使用较新式的格式化字符串字面量或 str.format() 有助于避免这些错误,这些可选的格式化方式也提供了更加强大、灵活以及可扩展的方法来格式化文本。

那么,如何使用 % 格式化语法呢?

string 类型的对象支持使用 % 运算符来执行字符串格式化操作。

例如:

>>> name = 'Eric'>>> 'Hello, %s' % name'Hello, Eric'

如果要插入多个变量,你必须使用 tuple 来包含这些变量。

>>> name = 'Eric'>>> age = 21>>> 'Hello %s. You are %s.' % (name, age)'Hello Eric. You are 21.'

上边这两段代码可读性还是不错的,但是,一旦你需要使用更多的变量和更长的格式字符串,代码的可读性就变得差很多了。

>>> first_name = 'Eric'>>> last_name = 'Idle'>>> age = 21>>> profession = 'comedian'>>> affiliation = 'Monty Python'>>> "Hello, %s %s. You are %s. You are a %s. You were a member of %s." % (first_name, last_name, age, profession, affiliation)'Hello, Eric Idle. You are 21. You are a comedian. You were a member of Monty Python.'

这段代码开始显得冗长,而且容易产生错误:你可能在格式字符串中漏写一个 %,或者未能正确显示 tuple 或 dict 对象。

幸运的是,格式化之路前途光明。


2,str.format() 方法

这是 Python 2.6 引入的新式格式化方法,能胜任 % 完成的所有工作。

str.format() 是 % 格式化语法的一个改进。它采用了正常的函数调用语法,并且可通过待格式化对象的 __format__() 方法进行扩展。

str.format() 在格式字符串中使用大括号为待格式化对象预留替换位。

>>> "Hello, {}. You are {}.".format(name, age)'Hello, Eric. You are 21.'

可以通过变量在 str.format() 参数中的位置索引来引用这些对象。

>>> "Hello, {1}. You are {0}.".format(age, name)'Hello, Eric. You are 21.'

也可以在格式字符串中插入变量名,这样你就能够传递对象,并在格式字符串的大括号里引用参数和方法。

>>> person = {'name': 'Eric', 'age': 21}>>> "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])'Hello, Eric. You are 21.'>>> "Hello, {name}. You are {age}.".format(age=person['age'], name=person['name'])'Hello, Eric. You are 21.'>>>>>> name = 'Eric'>>> age = 21>>> "Hello, {name1}. You are {age1}.".format(age1=age, name1=name)'Hello, Eric. You are 21.'

对于字典(dict)类型的变量,也可以使用 ** 来实现这个操作:

>>> person = {'name': 'Eric', 'age': 21}>>> "Hello, {name}. You are {age}.".format(**person)

str.format() 相比 % 格式化语法无疑是一个升级,但难称完美。

插入变量名使得它比 % 格式化语法更易读;可在参数中对字典类型对象执行解压操作,使得代码更简洁。但是处理多个参数或较长字符串时同样显得冗长。

>>> first_name = "Eric">>> last_name = "Idle">>> age = 21>>> profession = "comedian">>> affiliation = "Monty Python">>> "Hello, {first_name} {last_name}. You are {age}.You are a {profession}. You were a member of {affiliation}.".format(first_name=first_name, last_name=last_name, age=age, profession=profession, affiliation=affiliation)'Hello, Eric Idle. You are 21.You are a comedian. You were a member of Monty Python.'

【f-strings:一种新的改进的字符串格式化方法】

f-strings 是 Python 3.6 引入的一种新式字符串格式化方法,使得字符串格式化工作更简单。

f-strings 也称为格式化的字符串字面量,它以 f 开头,在引号包含的字符串中使用大括号包含待求值的表达式。这些表达式在运行时求值,然后通过 __format__ 协议实现格式化。

一起看一下 f-strings 是如何简化格式化操作的吧。


1,简单语法

f-strings 的基本语法和 str.format() 相似,但是更简洁。

>>> name = 'Eric'>>> age = 21>>> f'hello, {name}. You are {age}.''hello, Eric. You are 21.'

只需直接写一遍变量名即可。

也可以使用大写的 F 作为前缀:

>>> F"Hello, {name}. You are {age}."'Hello, Eric. You are 21.'

2,支持各种表达式

由于 f-strings 是在运行时求值,你可以在其中放置任意合法的 Python 表达式,这让你可以做一些很巧妙的事情。

你可以做一些很直接的事情:

>>> f'{2 * 37}''74'

也可以调用函数:

>>> def to_lowercase(input):... return input.lower()...>>> name = "Eric Idle">>> f"{to_lowercase(name)} is funny."'eric idle is funny.'

还可以直接调用类方法:

>>> f"{name.lower()} is funny."'eric idle is funny.'

你甚至可以在 f-strings 中格式化较复杂的对象,只要对象的类中恰当运用了 f-strings。

假设你有一个下边这样的类:

class Comedian: def __init__(self, first_name, last_name, age): self.first_name = first_name self.last_name = last_name self.age = age
def __str__(self): return f"{self.first_name} {self.last_name} is {self.age}."
def __repr__(self): return f"{self.first_name} {self.last_name} is {self.age}. Surprise!"

你可以这样直接格式化这个类的对象:

>>> new_comedian = Comedian("Eric", "Idle", "21")>>> f"{new_comedian}"'Eric Idle is 21.'

__str__() 和 __repr__() 方法用于处理对象如何表示为字符串,你至少应该在类定义中包含其中一个方法。如果只定义一个的话,请使用 __repr__(),因为它可用来替代 __str__()。

__str__() 返回的字符串是一个对象的非正式字符串表示,应该是可读的。__repr__() 返回的字符串是正式的表示,应该是明确的。

调用 str() 和 repr() 方法比直接使用 __str__() 和 __repr__() 要好。

默认情况下,f-strings 会使用 __str__() 来输出对象的字符串表示,但是如果你加入了转换标志 !r,f-strings 就会调用 __repr__()。

>>> f"{new_comedian}"'Eric Idle is 21.'>>> f"{new_comedian!r}"'Eric Idle is 21. Surprise!'

3,多行 f-strings

你可以在 f-strings 中使用多行字符串。

>>> name = "Eric">>> profession = "comedian">>> affiliation = "Monty Python">>> message = (... f"Hi {name}. "... f"You are a {profession}. "... f"You were in {affiliation}."... )>>> message'Hi Eric. You are a comedian. You were in Monty Python.'

但是请注意,你需要在多行字符串的每一行之前放置 f 前缀。否则,格式化结果会出错:

>>> message = (... f"Hi {name}. "... "You are a {profession}. "... "You were in {affiliation}."... )>>> message'Hi Eric. You are a {profession}. You were in {affiliation}.'

这段代码只有第一个变量名被替换为实际值。

你也可以使用转义符 \ 将 f-strings 扩展到多行。

>>> message = f"Hi {name}. " \... f"You are a {profession}. " \... f"You were in {affiliation}.">>>>>> message'Hi Eric. You are a comedian. You were in Monty Python.'

如果使用三引号字符串来定义多行 f-strings,输出的格式化字符串也将是多行的。

>>> message = f"""... Hi {name}.... You are a {profession}.... You were in {affiliation}.... """>>> message'\n\tHi Eric. \n\tYou are a comedian. \n\tYou were in Monty Python.\n'

4,运行速度

f-strings 中的 f 也可以代表 “fast”。通常情况下,f-strings 比 % 格式化语法和 str.format() 都要快。

如你所见,f-strings 实际上是一个运行时求值的表达式,而不是常量值。

运行时,大括号中的表达式先在其自己的作用域中求值,然后和 f-strings 的字符串常量部分组合在一起,并返回结果字符串。这就是 f-strings 的全部工作。

这里给出一个比较三种格式化方式速度的例子。

>>> import timeit>>> timeit.timeit("""name = "Eric"... age = 74... '%s is %s.' % (name, age)""", number = 10000)0.003324444866599663
>>> timeit.timeit("""name = "Eric"... age = 74... '{} is {}.'.format(name, age)""", number = 10000)0.004242089427570761
>>> timeit.timeit("""name = "Eric"... age = 74... f'{name} is {age}.'""", number = 10000)0.0024820892040722242

可以看出,f-strings 速度较快。

但结果并非总是如此,不同版本的 Python 中,str.format() 有时候会快一些。


【f-strings 的一些语法细节】

我们已经了解到 f-strings 拥有简洁的语法和较快的速度,在开始使用 f-strings之前,再来了解几点细节知识。

1,引号

在 f-strings 表达式中可以使用多种引号,但是 f-strings 内部表达式使用的引号和 f-strings 外部的引号不能相同。

下边这两种写法都是正确的:

>>> f"{'Eric Idle'}"'Eric Idle'>>> f'{"Eric Idle"}''Eric Idle'

也可以使用三引号:

>>> f"""Eric Idle"""'Eric Idle'>>> f'''Eric Idle''''Eric Idle'

如果你想在 f-strings 的内部和外部使用相同的引号,你需要使用转义符 \ 来转义内部引号:

>>> f"The \"comedian\" is {name}, aged {age}."'The "comedian" is Eric, aged 21.'

2,字典变量

当你打算在 f-strings 中插入字典变量的某些 key 时,若你使用单引号引用 key 名,你需要在 f-strings 的外部使用双引号。

>>> comedian = {'name': 'Eric Idle', 'age': 21}>>> f"The comedian is {comedian['name']}, aged {comedian['age']}."'The comedian is Eric Idle, aged 21.'

若你在 f-strings 的外部使用了和引用字典 key 相同的单引号,Python 解释器会报错:

>>> comedian = {'name': 'Eric Idle', 'age': 21}>>> f'The comedian is {comedian['name']}, aged {comedian['age']}.' File "<stdin>", line 1 f'The comedian is {comedian['name']}, aged {comedian['age']}.' ^SyntaxError: invalid syntax

所以,在 f-strings 中插入字典的 key 时,需要特别留意引号的使用方法。


3,大括号

由于 f-strings 使用大括号来插入变量,如果想在 f-strings 中输出 {} 字符,你需要使用双重大括号。

>>> f"{{70 + 4}}"'{70 + 4}'

但是,如果使用三重大括号,格式化结果中只会保留一重大括号:

>>> f"{{{70 + 4}}}"'{74}'

如果使用超过三重的大括号,你会在输出中得到更多大括号。

>>> f"{{{{70 + 4}}}}"'{{70 + 4}}'


4,反斜杠
f-strings 的字符串部分可以使用反斜杠来转义字符,但是其表达式部分却不可以使用反斜杠。
>>> name = 'Eric'>>> f"The \"comedian\" is {name}."'The "comedian" is Eric.'
>>> f"{\"Eric\"}" File "<stdin>", line 1SyntaxError: f-string expression part cannot include a backslash
可以像这段代码的上半部分那样,先对表达式求值,将结果存入变量,然后将变量名插入到 f-strings 中来避免这个报错。

5,内嵌评论
f-strings 的表达式部分不允许包含评论字符串,如果包含 # 开头的评论字符串,解释器会报错。
>>> f"Eric is {2 * 37 #Oh my!}." File "<stdin>", line 1SyntaxError: f-string expression part cannot include '#'

【结语】

f-strings 作为新式字符串格式化方法,在简洁性、可读性和运行速度上都优于其他方法,建议使用 Python 3.6 以上版本的小伙伴优先采用此方法来格式化字符串。


(0)

相关推荐

  • Python字符串格式化输出 & 函数(3.12)

    Python字符串格式化输出 &amp; 函数(3.12)

  • Python字符串及其简单格式化

    Python字符串及其简单格式化

  • 说说Python有几种字符串格式化?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • Python 字符串前面加u,r,b,f的含义

    字符串前加u 后面字符串以 Unicode格式进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时出现乱码. exp = u"我是含有中文字符组成的字符串." ...

  • Python字符串三种格式化输出

    字符串格式化输出是python非常重要的基础语法,今天就把三种格式化输出做一个简单的总结,希望对大家有帮助. 格式化输出:内容按照一定格式要求进行输出. 1.使用占位符%输出 python2.6版本之 ...

  • Python|字符串中第二大的数字

    问题描述给你一个混合字符串s,请你返回s中第二大的数字,如果不存在第二大的数字,请你返回-1.混合字符串由小写英文字母和数字组成.示例:输入:s = 'dfa12321afd'输出:2解决方案这是一道 ...

  • Python 和 Shell 语法终于可以互通了

    顶级架构师 1篇原创内容 Official Account 点击上方 '编程技术圈'关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 每日英文 Some happened ...

  • Python|快速掌握Python爬虫XPath语法

    Python|快速掌握Python爬虫XPath语法

  • .NET字符串格式化

    概述:我们在将一个类型(通常是数字和时间)转换成字符串时,可以控制其显示的样式.基本的写法就是在调用ToString或Format方法时提供格式化参数,由于具体的参数记不住,每次用到都要上网搜索一番, ...