假设你想输出一个人的名字和职业。你可以写一个简单的程序,如下所示。
# 定义变量 name = 'Mark' profession = 'Astronaut' age = 7 # 输出信息 output_string = ('My name is ' + name + ', I am ' + str(age) + ' years old ' + 'and my profession is ' + profession + '.') print(output_string)
My name is Mark, I am 7 years old and my profession is Astronaut.
这种方法缺乏简洁性和可读性。幸运的是,字符串插值提供了更好的解决方案。它允许将变量、表达式或函数输出直接插入字符串中,使字符串操作变得动态,并消除了手动连接的需要。
使用字符串插值的方法,我们可以将代码重写如下。
# 定义变量 name = 'Mark' profession = 'Astronaut' age = 7 # 输出信息 output_string = f'My name is {name}, I am {age} years old and my profession is {profession}.' print(output_string)
My name is Mark, I am 7 years old and my profession is Astronaut.
使用字符串插值的版本允许直接在字符串内部嵌入表达式,而无需使用繁琐的连接。正如你所看到的,这是一种更清晰的方法。
Python中的基本字符串插值
在Python中有几种不同的字符串插值技术。最常推荐的方法是格式化字符串文字,也称为f-strings,自Python 3.6起可用。
另一种方法,在 Python 3.6 之前的代码中常见,是 .format()
方法。虽然这种方法比 f-string 更冗长,但有时会有优势(具体细节如下)。
最后,您可能会在遗留代码中遇到 %
-风格的格式化。
使用 f-string(Python 3.6 及以上版本)
f-string(格式化字符串字面量)是 Python 中格式化字符串的一种强大而简洁的方法。它们在 Python 3.6 中引入,提供了一种可读且高效的方式,能够直接将变量、表达式和函数调用插入字符串中。
f-string基本语法的一个简单示例如下。
name = 'Mark' output_string = f'My name is {name}.' print(output_string)
My name is Mark.
在这段代码中,output_string
变量被赋值为一个f-string。 f
在开头引号之前的前缀表示该字符串支持嵌入表达式。变量 name
被求值并将其值插入到字符串中,最终输出为: "我的名字是Mark."
不仅变量值,计算或表达式也可以插入到f-string中。考虑这个例子。
import math a = 3.0 b = 4.0 # 使用字符串插值进行公式计算 print(f'The hypotenuse of a triangle with base {a} and side {b} is {math.sqrt(a ** 2 + b ** 2)}.')
The hypotenuse of a triangle with base 3.0 and side 4.0 is 5.0.
表达式 math.sqrt(a ** 2 + b ** 2)
直接在字符串中计算,从而消除了在将其插入字符串之前单独计算值的需要。
使用 .format() 方法
与 f-strings 类似,.format()
方法允许将变量和表达式插入字符串中。 .format()
方法的基本语法如下。
name = 'Mark' output_string = 'My name is {}.'.format(name) print(output_string)
My name is Mark.
大括号 {}
用作占位符,表示变量的值将在该位置插入到字符串中。插入到占位符中的具体变量值由传递给 .format()
方法的参数决定。
位置参数
如果需要多个占位符来对应多个变量会发生什么?请考虑以下代码。
name = 'Mark' age = 7 # 占位符按照参数的顺序填充 output_string = 'My name is {} and I am {} years old.'.format(name, age) print(output_string)
My name is Mark and I am 7 years old.
在这个例子中,需要两个变量,name
和 age
。因此,字符串中包含两个占位符,变量按照它们在 .format()
方法中出现的顺序插入。这些参数被称为 *位置* 参数,因为它们在字符串中的位置由它们在方法参数列表中的位置决定。
索引和命名占位符
作为占位符概念的一个变体,考虑这个例子。
name = 'Mark' age = 7 # 打印年龄两次 output_string = 'My name is {} and I am {} years old. My twin brother is also {} years old.'.format(name, age, age) print(output_string)
My name is Mark and I am 7 years old. My twin brother is also 7 years old.
在这里,我们重复使用了变量age
两次。像这样多次包含相同的变量显得笨拙,并且降低了可读性。有没有办法在使用.format()
方法格式化字符串时重用一个变量而不重复它?是的,有的,使用所谓的*索引占位符*。
name = 'Mark' age = 7 # 使用索引占位符 output_string = 'My name is {0} and I am {1} years old. My twin brother is also {1} years old.'.format(name, age) print(output_string)
My name is Mark and I am 7 years old. My twin brother is also 7 years old.
在这个例子中,我们在花括号内明确地定义了变量的顺序,遵循Python的零基索引。此外,我们在索引1处重用了变量,而不是重复它。
作为位置索引的替代方案,您还可以使用命名参数,每个参数都被赋予一个名称。
print('My name is {name} and I am {age} years old.'.format(name='Mark', age=7))
My name is Mark and I am 7 years old.
命名参数在指定其名称的花括号内进行评估。因此,{name}
占位符被 "Mark"
的值替换,而 {age}
占位符被 30
替换。
使用 % 运算符
字符串插值的最后一种方法是 %
操作符。它的功能类似于 C 语言中的 printf()
命令。由于其使用已被弃用,并强烈不推荐使用,建议使用 f-字符串或 .format()
方法。提到它是因为你可能会在遗留代码库中遇到它。
操作符的基本格式是:%
操作符是:"format string" % values
。格式字符串包含占位符,例如%s
代表字符串,这些占位符会被值替换。例如,以下示例打印“Hello, Mark。”
'Hello %s' % 'Mark'
'Hello Mark'
其他常见的格式说明符如下表所示。
说明符 |
含义 |
示例 |
---|---|---|
%s |
字符串 |
“Hello %s” % “Alice” → “Hello Alice” |
%d |
整数(十进制) |
“年龄: %d” % 25 → “年龄: 25” |
%f |
浮点数(默认6位小数) |
“圆周率: %f” % 3.14159 → “圆周率: 3.141590” |
%.nf |
浮点数(n位小数) |
“%.2f” % 3.14159 → “3.14” |
%x |
十六进制(小写) |
“%x” % 255 → “ff” |
%X |
十六进制(大写) |
“%X” % 255 → “FF” |
%o |
八进制 |
“%o” % 255 → “377” |
% 运算符有许多局限性。首先,它比 f-string 可读性差。考虑以下代码。
name = "Alice" age = 30 height = 5.6 # % 运算符难以扫描 message = "My name is %s, I am %d years old, and my height is %.1f feet." % (name, age, height) print(message)
My name is Alice, I am 30 years old, and my height is 5.6 feet.
这段代码一眼看上去清晰吗?可能不是。从占位符和填充空白的变量之间有大量的视觉解析来回切换。来回扫描很容易让人感到困惑(或头晕)。
现在,考虑使用 f-string 的等效代码。
# 这要干净得多 message = f"My name is {name}, I am {age} years old, and my height is {height:.1f} feet." print(message)
My name is Alice, I am 30 years old, and my height is 5.6 feet.
不需要扫描,也没有晦涩的格式化字符串。代码简洁、易于理解且易于编写。您可以通过 DataCamp 的 Python 编程技能课程学习其他编写清晰、优化代码的技巧。
高级 Python 字符串插值技术
现在我们已经了解了 Python 字符串插值的基础知识,让我们来看一些更高级的用法。
Python 多行字符串插值
f-string 也可以用于多行内容,方法是使用三重引号(单引号或双引号)加上 f 标识符。文本可以跨多行编写,输出将完全按照格式显示。
name = 'Mark' profession = 'Astronaut' age = 7 # 这是一个多行字符串的示例 bio = f""" Name: {name} Profession: {profession} Age: {age} """ print(bio)
Name: Mark Profession: Astronaut Age: 7
多行字符串也可以使用.format()
方法
name = 'Mark' profession = 'Astronaut' age = 7 # 这是一个使用.format()的多行字符串 bio = """ Name: {} Profession: {} Age: {} """.format(name, profession, age) print(bio)
Name: Mark Profession: Astronaut Age: 7
多行字符串插值的使用案例
你为什么想使用多行字符串插值?多行字符串插值有很多用途。以下是一些使用案例:
- 生成多行电子邮件或消息
- 日志记录和调试
- 动态生成SQL查询
生成多行电子邮件或消息
假设你正在向许多受邀者发送一封技术会议的表格信件。
name = "Alice" event = "Annual Tech Conference" date = "March 15, 2025" email = """Dear {name}, We are pleased to invite you to the {event} taking place on {date}. We hope you can join us for an exciting experience. Best regards, The Event Team""".format(name=name, event=event, date=date) print(email)
Dear Alice, We are pleased to invite you to the Annual Tech Conference taking place on March 15, 2025. We hope you can join us for an exciting experience. Best regards, The Event Team
使用f-字符串,创建表格信件简单且高效。要更改姓名、事件或日期,只需在变量中更改它们,字符串会自动更改。
日志记录和调试
多行字符串对于打印日志的错误消息非常有用。
error_code = 404 url = '/missing-page' timestamp = '2025-02-05 12:30:00' error_message = 'The requested page could not be found.' log_message = f"""[ERROR {error_code}] Time: {timestamp} URL: {url} {error_message}""" print(log_message)
[ERROR 404] Time: 2025-02-05 12:30:00 URL: /missing-page The requested page could not be found.
这种方法保持日志消息的结构化,使调试更容易,并且日志格式正确。
动态生成SQL查询
SQL查询可以使用多行字符串动态构建。
table = 'users' column = 'email' value = '[email protected]' query = f"""SELECT * FROM {table} WHERE {column} = '{value}';""" print(query)
SELECT * FROM users WHERE email = '[email protected]';
此方法使 SQL 查询易于阅读并保持缩进。此外,它消除了使用 +
进行字符串连接的需要。
其他用例包括:
- 编写格式化合同
- 创建 Markdown 或 $\LaTeX$ 文档
- 多行 HTML/XML 模板
- 生成API响应或类似JSON的文本
多行字符串插值的优点
正如我们所看到的,多行字符串插值有几个优点。
- 字符串插值在不需要转义字符
\n
的情况下保留格式。 - 与单行格式相比,字符串插值提高了可读性。
- 在处理结构化文本(例如日志、查询、报告)时,字符串插值减少了杂乱。
- 字符串插值允许动态生成文本而不破坏缩进。
格式化数字和特殊值
要控制使用 f-string 显示的小数位数,请使用以下语法:f'{value:.nf}'
,其中 value
是浮点数,n
是小数位数,f
(在 .
后面)表示浮点格式化。
举例来说,以下代码输出 $\pi$ 到不同的小数位数。
pi = 3.1415926535 print(f'Pi rounded to 2 decimal places: {pi:.2f}') print(f'Pi rounded to 4 decimal places: {pi:.4f}') print(f'Pi rounded to 0 decimal places: {pi:.0f}')
Pi rounded to 2 decimal places: 3.14 Pi rounded to 4 decimal places: 3.1416 Pi rounded to 0 decimal places: 3
使用 .format()
方法的格式化方式是类似的。
print('Pi rounded to 2 decimal places: {:.2f}'.format(pi)) print('Pi rounded to 4 decimal places: {:.4f}'.format(pi)) print('Pi rounded to 0 decimal places: {:.0f}'.format(pi))
Pi rounded to 2 decimal places: 3.14 Pi rounded to 4 decimal places: 3.1416 Pi rounded to 0 decimal places: 3
您可以使用 f-string 通过 :.nf
语法结合 %
来格式化百分比,其中 n
是小数位数。
score = 0.875 print(f"Success rate: {score:.2%}")
Success rate: 87.50%
您可以使用 f-string 格式化货币,使用 :,
作为千位分隔符,并使用 .nf
控制小数位数。您还可以在字符串中直接包含货币符号,如 $、€ 或 £。
amount = 98765.4321 print(f"USD: ${amount:,.2f}") print(f"EUR: €{amount:,.2f}") print(f"GBP: £{amount:,.2f}")
USD: $98,765.43 EUR: €98,765.43 GBP: £98,765.43
使用 f-string 与字典和列表
在 Python 中使用 f-string 与字典时,可以使用方括号表示法(dict[‘key’])在花括号内访问字典值,或者通过 ** 解包字典。
person = { 'name': 'Alice', 'age': 30, 'city': 'New York' } print(f"My name is {person['name']}, I am {person['age']} years old, and I live in {person['city']}.")
My name is Alice, I am 30 years old, and I live in New York.
您可以将字典解包到 f-string 中,如下所示,而无需手动访问每个键。
person = { 'name': 'Alice', 'age': 30, } print(f'My name is {name} and I am {age} years old.'.format(**person))
My name is Alice and I am 7 years old.
为了避免因缺少键而导致的错误,请使用 get()
进行字典访问。
person = {"name": "Alice"} # 错误:缺少键 'city' print(f"City: {person['city']}")
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[87], line 4 1 person = {"name": "Alice"} 3 # 错误:缺少键 'city' ----> 4 print(f"City: {person['city']}") KeyError: 'city'
print(f"City: {person.get('city', 'Not specified')}")
City: Not specified
字符串插值方法的优缺点
正如我们所看到的,f-字符串和.format()
方法都是字符串插值的有用方法。让我们比较一下每种方法的优缺点。
特性 |
f-字符串 |
.format() |
%格式化 |
---|---|---|---|
可读性 |
🟢 最佳 |
🟡 可以 |
🔴 较难 |
性能 |
🟢 最快 |
🟡 较慢 |
🔴 最慢 |
支持表达式 |
🟢 是 |
🟡 间接 |
🔴 否 |
多行支持 |
🟢 是 |
🟢 是 |
🔴 否 |
易用性 |
🟢 最简单 |
🟡 中等 |
🔴 难 |
调试(= 操作符) |
🟢 是(Python 3.8+) |
🔴 否 |
🔴 否 |
何时应该使用 .format()
而不是 f-strings?
优点 |
为什么使用 .format() |
---|---|
遗留的Python支持 |
适用于Python 2.7+ |
灵活的排序 |
允许轻松重新排序占位符 |
动态格式化 |
在格式说明符动态时有效 |
更好地处理{}大括号 |
避免额外的手动转义 |
与字典配合良好 |
更容易使用字典键 |
常见陷阱和最佳实践
下面是一些故障排除方法和使用Python字符串插值的顶级提示。
避免使用大括号的语法错误
在使用涉及大括号的字符串插值时,可能会出现许多语法错误。
- 确保每个 { 都有匹配的 }
print('Hello, my name is {name!'}
Cell In[96], line 1 print('Hello, my name is {name!'} ^ SyntaxError: closing parenthesis '}' does not match opening parenthesis '('
幸运的是,这个错误很简单,修复也很容易。
- 使用 {{ 和 }} 来显示字面上的 {}
如果你想在插值字符串中打印大括号,会发生什么?大括号内的任何内容都会被(尝试)评估。
print(f'Set notation: {a, b, c}')
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[101], line 1 ----> 1 print(f'Set notation: {a, b, c}') NameError: name 'c' is not defined
Python 将大括号内的 a, b, c 解释为一个元组,尝试找到与 a 相关联的值。由于没有这样的变量,所以会引发 KeyError。修复方法是使用双大括号 {{}}
.
print("Set notation: {{a, b, c}}")
集合表示法:{{a, b, c}}
性能比较:f-strings 与 .format()
让我们比较 f-strings 和 .format()
.
import timeit name = "Alice" age = 30 pi = 3.1415926535 # 测量 f-string 性能 f_string_time = timeit.timeit('f"My name is {name} and I am {age} years old."', globals=globals(), number=1000000) # 测量 .format() 性能 format_time = timeit.timeit('"My name is {} and I am {} years old.".format(name, age)', globals=globals(), number=1000000) # 测量带表达式的 f-string 性能 f_string_expr_time = timeit.timeit('f"Pi rounded to 2 decimal places: {pi:.2f}"', globals=globals(), number=1000000) # 测量带表达式的 .format() 性能 format_expr_time = timeit.timeit('"Pi rounded to 2 decimal places: {:.2f}".format(pi)', globals=globals(), number=1000000) # 打印结果 print(f"f-string (simple): {f_string_time:.6f} seconds") print(f".format() (simple): {format_time:.6f} seconds") print(f"f-string (with expression): {f_string_expr_time:.6f} seconds") print(f".format() (with expression): {format_expr_time:.6f} seconds")
f-string (simple): 0.080447 seconds .format() (simple): 0.129860 seconds f-string (with expression): 0.123171 seconds .format() (with expression): 0.146242 seconds
如你所见,从效率的角度来看,应该优先选择 f-string 而不是 .format()
。
清晰可读的字符串插值最佳实践
为了确保你的字符串格式化清晰、高效且易于维护,使用插值字符串时请遵循以下最佳实践。
- 优先使用 f-string 以提高可读性(Python 3.6+)
# 推荐 name = "Alice" age = 30 print(f"My name is {name} and I am {age} years old.") # 不推荐(可读性差) print("My name is {} and I am {} years old.".format(name, age)) # 避免使用 % 格式化(过时) print("My name is %s and I am %d years old." % (name, age))
My name is Alice and I am 30 years old. My name is Alice and I am 30 years old. My name is Alice and I am 30 years old.
- 使用命名占位符以提高清晰度
# 命名占位符(可读性强) user = {"name": "Alice", "age": 30} print(f"My name is {user['name']} and I am {user['age']} years old.") # 在 .format() 中使用索引(可读性较差) print("My name is {0} and I am {1} years old.".format("Alice", 30))
My name is Alice and I am 30 years old. My name is Alice and I am 30 years old.
- 保持多行字符串的可读性。
name = "Alice" age = 30 message = f"""Hello, {name}! We are happy to invite you to our event. At {age} years old, you are eligible for the VIP pass. Best regards, Event Team """ print(message)
Hello, Alice! We are happy to invite you to our event. At 30 years old, you are eligible for the VIP pass. Best regards, Event Team
- 在日志中使用 f-strings 以便于调试
Python 3.8 及更高版本支持 =
在 f-strings 中进行调试。
value = 42 # Output: value = 42 print(f"{value = }")
value = 42
结论
字符串插值是 Python 中一个强大的特性,使得字符串格式化更加简洁、可读和高效。在可用的方法中,f-strings 是最现代且推荐的方法,相较于旧的方法如 .format()
和 %
格式化,提供了更好的性能、清晰度和灵活性。
通过遵循最佳实践,例如使用命名占位符、控制小数精度、对齐文本以提高可读性,以及优雅地处理缺失的字典键,您可以在Python中编写干净、专业且易于维护的字符串格式化代码。
无论您是在生成格式化报告、多行消息还是结构化数据输出,f-strings都提供了一种简单而强大的方式来无缝集成变量和表达式。采用f-strings不仅会提高您的代码质量,还会增强其效率。
有关Python字符串插值的更多信息,请查看DataCamp的资源:
Source:
https://www.datacamp.com/tutorial/python-string-interpolation