f-string是Python3.6提供的一种新的格式化字符串的方法。 与其他格式化方式相比,代码更具可读性,更简洁且不易出错,而且速度更快! 在本文中,您将了解如何以及为什么现在就开始使用f-string。在使用f-string之前,我们还是先了解下之前是如何处理格式化的。
Python中的“老式”字符串格式
在Python 3.6之前,有两种方法可以将Python表达式嵌入字符串字面量进行格式化:%-formatting和str.format()。您将看到如何使用它们以及它们的局限性。
选项1:%格式
这是Python格式化的元老方式,从一开始就存在于该语言中。你可以在Python文档中阅读更多内容。请记住,%-formatting不被python文档推荐,文档中包含以下注意事项:
“这里描述的格式化操作会表现出各种古怪,导致许多常见错误(例如未能正确显示元组和字典)。 使用较新的格式化字符串文字或str.format()接口有助于避免这些错误。 替代方案还提供了更强大,灵活和可扩展的文本格式化方法。” https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting
如何使用%-formatting
字符串对象有一个使用%操作符的内置操作,您可以使用该操作符来格式化字符串。下面是实际情况:
>>> name = "Eric" >>> "Hello, %s." % name 'Hello, Eric.'
为了插入多个变量,必须使用这些变量的元组。你应该这样做:
>>> name = "Eric" >>> age = 74 >>> "Hello, %s. You are %s." % (name, age) 'Hello, Eric. You are 74.'
为什么%-formatting不是很好
您刚才看到的代码还尚可阅读。然而,一旦开始使用几个参数和更长的字符串,代码将很快变得不太容易阅读。
>>> first_name = "Eric" >>> last_name = "Idle" >>> age = 74 >>> 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 74. You are a comedian. You were a member of Monty Python.'
所以这种格式并不是很好,因为它很冗长,而且会导致错误,比如不能正确地显示元组或字典。幸运的是,未来的日子会更加光明。
选项2:str.format()
Python 2.6中引入了字符格式化的新方法str.format()
如何使用str.format()
str.format()是对%-formatting的改进。它使用普通函数调用语法,并可通过转换为字符串对象的__format__()方法进行扩展。
对于str.format(),替换字段用花括号标记:
>>> "Hello, {}. You are {}.".format(name, age) 'Hello, Eric. You are 74.'
通过引用变量的索引,你可以以任何顺序引用变量:
>>> "Hello, {1}. You are {0}.".format(age, name) 'Hello, Eric. You are 74.'
但如果你插入了变量名,你就可以在括号之间传递对象,然后引用参数和方法:
>>> person = {'name': 'Eric', 'age': 74} >>> "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age']) 'Hello, Eric. You are 74.'
你也可以使用**来处理字典,使代码更加简洁:
>>> person = {'name': 'Eric', 'age': 74} >>> "Hello, {name}. You are {age}.".format(**person) 'Hello, Eric. You are 74.'
与%-formatting相比,str.format()绝对是一个升级,但它并不是一帆风顺的。
为什么str.format()不好
使用str.format()的代码比使用%-formatting的代码更容易读懂,但是当你处理多个参数和较长的字符串时,str.format()仍然可能相当冗长。比如下面的代码:
>>> first_name = "Eric" >>> last_name = "Idle" >>> age = 74 >>> profession = "comedian" >>> affiliation = "Monty Python" >>> print(("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 74. You are a comedian. You were a member of Monty Python.'
如果在字典中有想要传递给.format()的变量,那么只需使用.format(**some_dict)对其进行解包,并在字符串中按键引用值,但必须有更好的方法来做到这一点。
f-Strings: Python中格式化字符串的一种新的改进方法
f-strings是字符串字面量,它以f开头,花括号包含的表达式将被它们的值所替换。表达式在运行时计算,然后使用__format__协议进行格式化。和往常一样,当你想了解更多的时候,Python文档是你的朋友。
以下是f-strings可以让你的生活更轻松的一些方法。
简单语法
语法类似于您使用str.format()时使用的语法,但更简洁。看看这是多么容易读懂:
>>> name = "Eric" >>> age = 74 >>> f"Heloo, {name}. You are {age}." 'Heloo, Eric. You are 74.'
也可以使用大写字母F:
>>> F"Heloo, {name}. You are {age}." 'Heloo, Eric. You are 74.'
任意的表达式
因为f-string是在运行时计算的,所以可以在其中放入任何和所有有效的Python表达式。这允许你做一些漂亮的事情。
你可以做一些非常简单的事情,像这样:
>>> f"{2*40}" '80'
但是你也可以调用函数。这里有一个例子:
>>> def to_lowercase(input): ... return input.lower() ... >>> name = "Liu DeHua" >>> f"{to_lowercase(name)} is funny." 'liu dehua is funny.'
你也可以直接调用一个方法:
>>> f"{name.lower()} is funny." 'liu dehua is funny.'
您甚至可以使用由带有f-string的类创建的对象。假设你有下面的class:
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", "74") >>> f"{new_comedian}" 'Eric Idle is 74.'
__str__()和__repr__()方法处理对象如何使用字符串表示,因此您需要确保在类定义中至少包含这些代码。如果你必须选择一个,使用__repr__(),因为它可以用来代替__str__()。
str()返回的字符串是对象的非正式字符串表示形式,应该是可读的。repr()返回的字符串是正式的表示形式,应该是无二义性的。调用str()和repr()比直接使用__str__()和__repr__()更可取。
默认情况下,f-strings将使用__str__(),但如果你包含转换标志,你可以确保它们使用__repr__() !
>>> f"{new_comedian}" 'Eric Idle is 74.' >>> f"{new_comedian!r}" 'Eric Idle is 74. Surprise!'
多行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放在每一行的前面,那么它就是的普通的字符串,不会有格式化效果,如果你想把字符串分散到多行,你也可以选择用\来转义返回:
>>> 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.'
但如果你使用""",会发生这样的情况:
>>> 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'
速度
f字符串中的f也可以代表“快”。f-string比%-formatting和str.format()都要快。正如您已经看到的,f-string是在运行时计算的表达式,而不是常量值。以下是这些文档的摘录:
”F-strings提供了一种方法,使用最小的语法将表达式嵌入到字符串字面量中。应该注意的是,f-string实际上是在运行时计算的表达式,而不是常量值。在Python源代码中,f-string是一个前缀为f的文字字符串,它包含大括号中的表达式。表达式被它们的值代替。”
在运行时,花括号内的表达式在它自己的范围内计算,然后与f-string的字符串文字部分放在一起。然后返回结果字符串。
这里是一个速度的比较:
>>> timeit.timeit("""name = "Eric" ... age = 74 ... '%s is %s.' % (name, age)""", number = 100000) 0.019910944000002928
>>> timeit.timeit("""name = "Eric" ... age = 74 ... '{} is {}.'.format(name, age)""", number = 100000) 0.03233340299999554
>>> timeit.timeit("""name = "Eric" ... age = 74 ... f'{name} is {age}'""", number = 100000) 0.017086811000012858
如你所见,f-string速度最快。
然而,情况并非总是如此。当它们第一次被实现时,还是有一些速度问题,需要比str.format()更快。引入了一个特殊的BUILD_STRING操作码。
Python f-Strings:讨厌的细节
可以在表达式内使用各种类型的引号。只是要确保在f-string的外部使用的引号类型与在表达式中使用的引号类型不同。
这段代码可以工作:
>>> f"{'Eric Idle'}" 'Eric Idle'
下面这段代码也可以运行:
>>> f'{"Eric Idle"}' 'Eric Idle'
你也可以使用三引号:
>>> f"""Eric Idle""" 'Eric Idle'
>>> f'''Eric Idle''' 'Eric Idle'
如果你发现你需要在字符串的内部和外部使用相同类型的引号,那么你可以用\:
>>> f"The \"comedian\" is {name}, aged {age}." 'The "comedian" is Eric Idle, aged 74.'
字典
说到引号,在使用词典时要特别当心。如果您打算对字典中的键使用单引号,那么请记住确保对包含键的f-string使用双引号。
这将工作:
>>> comdian = {'name': 'Eric Idle', 'age': 74} >>> f"The comedian is {comdian['name']}, aged {comdian['age']}." 'The comedian is Eric Idle, aged 74.'
但下面的代码会导致语法错误:
>>> comdian = {'name': 'Eric Idle', 'age': 74} >>> f'The comedian is {comdian['name']}, aged {comdian['age']}.' File "<stdin>", line 1 f'The comedian is {comdian['name']}, aged {comdian['age']}.' ^ SyntaxError: invalid syntax
如果在字典键周围使用与在f-string外部相同类型的引号,那么第一个字典键开头的引号将被解释为字符串的结束。
括号
为了让大括号出现在字符串中,你必须使用双大括号:
>>> f"{{70 + 4}}" '{70 + 4}'
注意,使用三括号将导致在你的字符串中只有一个括号:
>>> f"{{{70 + 4}}}" '{74}'
反斜杠
如前所述,可以在f-string的字符串部分中使用反斜杠转义。但是,你不能在f-string的表达式部分使用反斜杠来转义:
>>> f"{\"Eric Idle\"}" File "<stdin>", line 1 SyntaxError: f-string expression part cannot include a backslash
你可以通过预先计算表达式并在f-string中使用结果来解决这个问题:
>>> name = "Eric Idle" >>> f"{name}" 'Eric Idle'
内联注释
表达式不应该包含使用#符号的注释。你会得到一个语法错误:
>>> f"Eric is {2 * 37 #Oh my!}." File "<stdin>", line 1 f"Eric is {2 * 37 #Oh my!}." ^ SyntaxError: f-string expression part cannot include '#'
前进并使用格式化!
您仍然可以使用旧的格式化字符串的方法,但是有了f-strings,您现在有了一种更简洁、可读和方便的方法,既更快又不容易出错。根据《Zen of Python》,当你决定如何做某事时,“这里应该有一个——最好只有一个——明显的方法来做这件事。”虽然f-strings不是你格式化字符串的唯一可能的方式,但它们处于一个很好的位置,成为一种明显的方式来完成这项工作。