跳至主要内容

Python 字符串插值:初学者指南

了解 Python 字符串插值、其用途及适用场景。包含实用示例与最佳实践。
· 10分钟 阅读

使用 AI 探索

假设您想输出某个人的姓名和职业。您可以编写如下的简单程序。

# Define variables
name = 'Mark'
profession = 'Astronaut'
age = 7


# Output info
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.

这种做法不够简洁且可读性一般。幸运的是,字符串插值提供了更好的解决方案。它允许将变量、表达式或函数输出直接插入到字符串中,使字符串处理更加动态,并且无需手动拼接。

使用字符串插值方法,我们可以将代码改写如下。

# Define variables
name = 'Mark'
profession = 'Astronaut'
age = 7


# Output info
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-strings 更啰嗦,但在某些情况下也有优势(见下文)。

最后,您可能会在遗留代码中遇到 % 风格的格式化。

使用 f-strings(Python 3.6+)

f-strings(格式化字符串字面量)是 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 会被求值,其结果被插入到字符串中,从而得到输出: "My name is Mark."

不仅可以插入变量值,还可以在 f-strings 中插入计算或表达式。看下面的示例。

import math


a = 3.0
b = 4.0


# Use string interpolation for the formula
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() 方法也可以将变量与表达式插入字符串。其基本语法如下。

name = 'Mark'
output_string = 'My name is {}.'.format(name)
print(output_string)
   My name is Mark.

花括号 {} 充当占位符,表示将在该位置插入变量的值。插入到占位符中的具体变量由传给 .format() 方法的参数决定。

位置参数

如果需要为多个变量设置多个占位符会怎样?请看下面的代码。

name = 'Mark'
age = 7


# The placeholders are filled in order of the arguments
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


# Print age twice
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


# Use indexed placeholders
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-strings 或 .format() 方法。之所以在此提及,是因为您可能会在遗留代码库中遇到它。

% 运算符的基本格式是: "format string" % values。格式字符串包含占位符,例如 %s 表示字符串,它会被对应的值替换。比如,下面的示例会打印 "Hello, Mark."

'Hello %s' % 'Mark'
   'Hello Mark'

其他常见的格式说明符如下表所示。

说明符

含义

示例

%s

字符串

"Hello %s" % "Alice" → "Hello Alice"

%d

整数(十进制)

"Age: %d" % 25 → "Age: 25"

%f

浮点数(默认 6 位小数)

"Pi: %f" % 3.14159 → "Pi: 3.141590"

%.nf

浮点数(n 位小数)

"%.2f" % 3.14159 → "3.14"

%x

十六进制(小写)

"%x" % 255 → "ff"

%X

十六进制(大写)

"%X" % 255 → "FF"

%o

八进制

"%o" % 255 → "377"

% 运算符有很多限制。首先,它的可读性不如 f-strings。看下面的代码。

name = "Alice"
age = 30
height = 5.6


# The % operator is hard to scan
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-strings 的等效代码。

# This is much cleaner
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 Programming 技能路径学习更多编写清晰、优化代码的技巧。

Python 字符串插值的高级技巧

了解了 Python 字符串插值的基础之后,我们再来看一些更高级的用法。

Python 多行字符串插值

通过在三引号(单引号或双引号)前使用 f 标识符,f-strings 也可用于多行内容。文本可以跨多行书写,并会按所写格式原样输出。

name = 'Mark'
profession = 'Astronaut'
age = 7


# This is an example of a multiline string
bio = f"""
Name: {name}
Profession: {profession}
Age: {age}
"""
print(bio)
   Name: Mark

   Profession: Astronaut

   Age: 7

多行字符串也可以使用 .format() 方法创建。

name = 'Mark'
profession = 'Astronaut'
age = 7


# This is a multiline string with .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-strings,创建模板信既简单又高效。要更改姓名、活动或日期,只需修改相应变量,字符串就会“自动魔法般地”更新。

日志记录与调试

多行字符串有助于输出用于日志的错误信息。

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-strings 与字典和列表一起使用

要在 Python 中将 f-strings 与字典一起使用,可在花括号内使用方括号语法(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"}


# Error: key 'city' is missing
print(f"City: {person['city']}") 
   ---------------------------------------------------------------------------




   KeyError                                  Traceback (most recent call last)




   Cell In[87], line 4

         1 person = {"name": "Alice"}

         3 # Error: key 'city' is missing

   ----> 4 print(f"City: {person['city']}")







   KeyError: 'city'
print(f"City: {person.get('city', 'Not specified')}")
   City: Not specified

字符串插值方法的优缺点

如前所述,f-strings 和 .format() 方法都是有用的字符串插值方式。下面我们对两种方法的优缺点进行对比。

特性

f-strings

.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 vs .format()

我们来比较一下 f-strings 与 .format() 的性能。

import timeit


name = "Alice"
age = 30
pi = 3.1415926535


# Measure f-string performance
f_string_time = timeit.timeit('f"My name is {name} and I am {age} years old."', globals=globals(), number=1000000)


# Measure .format() performance
format_time = timeit.timeit('"My name is {} and I am {} years old.".format(name, age)', globals=globals(), number=1000000)


# Measure f-string performance with expressions
f_string_expr_time = timeit.timeit('f"Pi rounded to 2 decimal places: {pi:.2f}"', globals=globals(), number=1000000)


# Measure .format() performance with expressions
format_expr_time = timeit.timeit('"Pi rounded to 2 decimal places: {:.2f}".format(pi)', globals=globals(), number=1000000)


# Print results
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-strings 而非 .format()。

实现清晰可读的字符串插值的最佳实践

为确保字符串格式化清晰、高效且易维护,使用插值字符串时请遵循以下最佳实践。

  • 在 Python 3.6+ 中优先使用 f-strings 以提升可读性
# Recommended
name = "Alice"
age = 30
print(f"My name is {name} and I am {age} years old.")


# Not Recommended (Less readable)
print("My name is {} and I am {} years old.".format(name, age))


# Avoid using % formatting (Outdated)
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.
  • 使用命名占位符以增强清晰度
# Named placeholders (readable)
user = {"name": "Alice", "age": 30}
print(f"My name is {user['name']} and I am {user['age']} years old.")


# Using indexes in .format() (not as readable)
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 的资源:

Python 字符串插值常见问答

什么是 Python 中的字符串插值?

字符串插值是将变量、表达式或函数输出直接插入到字符串中的过程。Python 通过 f-strings、.format() 和 % 格式化来支持它。

f-strings 在所有 Python 版本中都可用吗?

不是。f-strings 是在 Python 3.6 引入的。如果您使用更旧的版本,需要改用 .format() 或 % 格式化。

为何 f-strings 优于 .format() 和 % 格式化?

f-strings 比 .format() 和 % 格式化更快、更易读且更简洁。它们允许直接嵌入变量和内联表达式,因此更高效。

可以在字典中使用 f-strings 吗?

可以,您可以在 f-strings 中访问字典的值:

user = {"name": "Alice", "age": 30}
print(f"My name is {user['name']} and I am {user['age']} years old.")

或者,解包字典:

print(f"My name is {name} and I am {age}.".format(**user))
如何使用 f-strings 格式化数字?

您可以使用格式说明符控制小数位并添加千位分隔符:

pi = 3.14159
print(f"Pi: {pi:.2f}")
Mark Pedigo

作者

Mark Pedigo

Mark Pedigo(博士)是一位在医疗数据科学、编程与教育领域具有深厚专长的资深数据科学家。Mark 拥有数学博士学位、计算机科学学士学位以及人工智能专业证书,兼具扎实的技术底蕴与务实的解决问题能力。他的职业经历涵盖欺诈检测、婴儿死亡率预测与财务预测,并参与了 NASA 成本估算软件的研发。作为教育工作者,他曾在 DataCamp 和圣路易斯华盛顿大学任教,并指导初级程序员。在闲暇时间,Mark 与妻子 Mandy 和爱犬 Harley 一起享受明尼苏达的户外时光,并演奏爵士钢琴。

主题