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 以上版本的小伙伴优先采用此方法来格式化字符串。
谢绝搬运,抄袭必究