从 Python 3.6 开始,f-strings
是一种很好的格式化字符串的新方法。它们不仅比其他格式化方式更易读、更简洁、更不容易出错,而且速度也更快!
在本文结束时,您将了解如何以及为什么从今天开始使用 f-string。
Python f-string字符串格式化的介绍
在 Python 3.6 之前,有两种主要方法可以将 Python 表达式嵌入到字符串文字中以进行格式化:%-formatting
和str.format()
. 您将看到如何使用它们以及它们的局限性。
这是 Python 格式化的 OG,从一开始就在该语言中。
您可以在 Python 文档中阅读更多内容。请记住,文档不建议使用 %-formatting,其中包含以下注释:
这里描述的格式化操作表现出各种quirks,这些quirks会导致一些常见错误(例如无法正确显示元组和字典)
使用较新的格式化字符串文字或 str.format() 接口有助于避免这些错误。 这些替代方案还为格式化文本提供了更强大、更灵活和可扩展的方法。
格式化符号 | 功能 |
---|---|
%s | 格式化字符串 |
%c | 格式化字符及其ASCII码 |
%d | 格式化十进制整数 |
%o | 格式化八进制数 |
%x / %X | 格式化十六进制数(x / X 代表转换后的十六进制字符的大小写) |
%f | 格式化浮点数字 |
字符串对象有一个使用 % 运算符的内置操作,可以使用它来格式化字符串。
>>> name = "Eric"
>>> "Hello, %s." % name
'Hello, Eric.'
为了插入多个变量,必须使用这些变量的元组。
>>> name = "Eric"
>>> age = 74
>>> "Hello, %s. You are %s." % (name, age)
'Hello Eric. You are 74.'
上面看到的代码示例具有足够的可读性。但是,一旦开始使用多个参数和更长的字符串,代码将很快变得不那么容易阅读。事情已经开始看起来有点乱了:
>>> 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.'
这种格式不是很好,因为它很冗长并且会导致错误,比如不能正确显示元组或字典。
这种完成工作的新方法是在 Python 2.6 中引入的。可以查看较新的 Python 字符串格式技术指南以获取更多信息。
str.format() 是对 %-formatting 的改进。它使用正常的函数调用语法,并且可以通过正在转换为字符串的对象上的 format() 方法进行扩展。
使用 str.format(),替换字段用大括号标记:
>>> name = "Eric"
>>> age = 74
>>> "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() 的代码比使用 %-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)
解压它并通过字符串中的键引用值,但必须有一个更好的方法来做到这一点。
一种在 Python 中格式化字符串的新方法和改进方法
f-string亦称为格式化字符串常量(formatted string literals)
是Python3.6引入的一种字符串格式化方法,主要目的是使格式化字符串的操作更加简便。
f-string在功能方面不逊于传统的 %-formatting 语句和 str.format() 函数
同时性能又优于二者,且使用起来也更加简洁明了,因此对于Python3.6及以后的版本,推荐使用f-string进行字符串格式化。
语法类似于使用 str.format() 的语法,但不那么冗长。
>>> name = "Eric"
>>> age = 74
>>> f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'
使用大写字母 F 也是有效的:
>>> F"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'
因为 f-strings 是在运行时评估的,所以您可以将任何和所有有效的 Python 表达式放入其中。这使您可以做一些漂亮的事情。
可以做一些非常简单的事情,像这样:
>>> f"{2 * 37}"
'74'
也可以调用函数
def to_lowercase(input):
return input.lower()
name = "Eric Idle"
f"{to_lowercase(name)} is funny."
还可以选择直接调用方法:
>>> f"{name.lower()} is funny."
'eric idle is funny.'
甚至可以使用从具有 f-strings 的类创建的对象。假设有以下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__()
,但如果包含转换标志 !r,则可以确保它们使用 __repr__()
:
>>> f"{new_comedian}"
'Eric Idle is 74.'
>>> f"{new_comedian!r}"
'Eric Idle is 74. Surprise!'
如果您想阅读一些导致 f-strings 支持完整 Python 表达式的对话,您可以在此处进行。
可以有多行字符串:
>>> 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}.'
如果想将字符串分散到多行,还可以选择使用 \ 转义返回:
>>> 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 Hi Eric.\n You are a comedian.\n You were in Monty Python.\n'
f-strings中的 f 也可以代表“fast”。
f-strings 比 %-formatting 和 str.format() 都快。 正如您已经看到的,f 字符串是在运行时计算的表达式,而不是常量值。 这是文档的摘录:
F-strings 提供了一种在字符串文字中嵌入表达式的方法,使用最少的语法。
应该注意的是,f-string 实际上是在运行时计算的表达式,而不是常量值。
在 Python 源代码中,f-string 是一个以 f 为前缀的文字字符串,其中包含大括号内的表达式。 表达式被替换为它们的值。
在运行时,花括号内的表达式在其自己的范围内进行评估,然后与 f-string 的字符串文字部分放在一起。然后返回结果字符串。这就是全部。
速度比较:
>>> 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-string 速度更快
然而,情况并非总是如此。当它们第一次实现时,它们存在一些速度问题,需要比 str.format() 更快。引入了特殊的 BUILD_STRING opcode。
可以在表达式中使用各种类型的引号。只需确保在 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-strings 使用双引号。
>>> comedian = {'name': 'Eric Idle', 'age': 74}
>>> f"The comedian is {comedian['name']}, aged {comedian['age']}."
The comedian is Eric Idle, aged 74.
但这将是一个常犯语法错误:
>>> comedian = {'name': 'Eric Idle', 'age': 74}
>>> f'The comedian is {comedian['name']}, aged {comedian['age']}.'
File "" , line 1
f'The comedian is {comedian['name']}, aged {comedian['age']}.'
^
SyntaxError: invalid syntax
如果您在字典键周围使用与在 f-string 外部使用相同类型的引号,则第一个字典键开头的引号将被解释为字符串的结尾。
为了使大括号出现在您的字符串中,您必须使用双大括号:
>>> f"{{70 + 4}}"
'{70 + 4}'
请注意,使用三重大括号将导致字符串中只有一个大括号:
>>> f"{{{70 + 4}}}"
'{74}'
但是,如果您使用三个以上的大括号,您可以获得更多的大括号:
>>> f"{{{{70 + 4}}}}"
'{{70 + 4}}'
正如您之前看到的,您可以在 f-string 的字符串部分使用反斜杠转义。但是,您不能在 f-string 的表达式部分使用反斜杠转义:
>>> f"{\"Eric Idle\"}"
File "" , line 1
f"{\"Eric Idle\"}"
^
SyntaxError: f-string expression part cannot include a backslash
您可以通过预先评估表达式并使用 f 字符串中的结果来解决此问题:
>>> name = "Eric Idle"
>>> f"{name}"
'Eric Idle'
表达式不应包含使用 # 符号的注释。你会得到一个语法错误:
>>> f"Eric is {2 * 37 #Oh my!}."
File "" , line 1
f"Eric is {2 * 37 #Oh my!}."
^
SyntaxError: f-string expression part cannot include '#'