Python F-Strings:字符串格式化完全指南
Updated on
字符串格式化是 Python 中最常见的操作之一,但多年来一直是令人头疼的问题。% 运算符使用从 C 语言借鉴来的晦涩格式代码。.format() 方法将值分散在模板的各处。使用 + 进行字符串拼接迫使你手动转换类型,并产生混乱、难以阅读的代码。每种方法都让本应简单的任务——将值放入字符串中——变得繁琐。
在实际项目中,这个问题更加严重。你需要将货币格式化为两位小数、对齐报告中的列、用前导零填充数字、显示百分比、格式化时间戳——同时保持代码的可读性。使用旧的格式化方法,你最终要维护两个并行结构:模板字符串和参数列表。一个简单的重新排序错误就会无声地破坏一切,产生错误的输出而不是报错。
Python 3.6 引入了 f-strings(格式化字符串字面值),永久改变了字符串格式化的方式。通过在字符串前加上 f 并将表达式直接嵌入 {花括号} 内,f-strings 让值出现在它们应该出现的位置旁边。它们比所有其他格式化方法都快。它们支持完整的格式规范范围。而且在 Python 3.8 中,它们通过 = 说明符获得了内置的调试功能。本指南涵盖 f-strings 的每一项功能,并提供实用的可运行示例。
什么是 F-Strings?
F-strings,正式名称为"格式化字符串字面值"(formatted string literals),在 PEP 498 (opens in a new tab) 中引入,并随 Python 3.6 发布。概念很简单:在任何字符串前加上 f(或 F),Python 会在运行时计算花括号 {} 内的任何表达式,将结果转换为字符串并插入到输出中。
name = "Alice"
age = 30
greeting = f"My name is {name} and I am {age} years old."
print(greeting)
# Output: My name is Alice and I am 30 years old.f 前缀适用于单引号、双引号和三引号:
single = f'Hello, {name}'
double = f"Hello, {name}"
triple_double = f"""Hello, {name}"""
triple_single = f'''Hello, {name}'''在底层,Python 在解析时将 f-strings 编译为一系列字符串拼接和 format() 操作。这就是 f-strings 比你手动调用 .format() 更快的原因——解释器直接优化了该操作。
基础 F-String 语法
核心语法很简单:编写 f"文本 {表达式} 更多文本"。Python 计算表达式,对结果调用 str(),并将其插入字符串。
# Variables
city = "Tokyo"
population = 13960000
print(f"{city} has a population of {population}.")
# Output: Tokyo has a population of 13960000.
# You can use either f or F
print(F"Welcome to {city}!")
# Output: Welcome to Tokyo!你可以在单个 f-string 中放置任意数量的表达式:
first = "Grace"
last = "Hopper"
title = "Rear Admiral"
year = 1906
bio = f"{title} {first} {last}, born {year}, lived to {1992 - year} years."
print(bio)
# Output: Rear Admiral Grace Hopper, born 1906, lived to 86 years.F-Strings 中的表达式
F-strings 不仅仅是插入变量。它们计算花括号之间的任何有效 Python 表达式。这包括算术运算、方法调用、函数调用、三元表达式、列表索引、字典访问等。
算术和数学运算
x = 15
y = 4
print(f"{x} + {y} = {x + y}")
print(f"{x} / {y} = {x / y:.2f}")
print(f"{x} ** {y} = {x ** y}")
print(f"{x} % {y} = {x % y}")
# Output:
# 15 + 4 = 19
# 15 / 4 = 3.75
# 15 ** 4 = 50625
# 15 % 4 = 3方法调用
text = " hello, python world "
print(f"Stripped: '{text.strip()}'")
print(f"Title case: '{text.strip().title()}'")
print(f"Upper: '{text.strip().upper()}'")
print(f"Replace: '{text.strip().replace('python', 'f-string')}'")
# Output:
# Stripped: 'hello, python world'
# Title case: 'Hello, Python World'
# Upper: 'HELLO, PYTHON WORLD'
# Replace: 'hello, f-string world'函数调用
def calculate_bmi(weight_kg, height_m):
return weight_kg / (height_m ** 2)
weight = 70
height = 1.75
print(f"BMI: {calculate_bmi(weight, height):.1f}")
# Output: BMI: 22.9
# Built-in functions
items = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Items: {items}")
print(f"Count: {len(items)}, Sum: {sum(items)}, Min: {min(items)}, Max: {max(items)}")
# Output:
# Items: [3, 1, 4, 1, 5, 9, 2, 6]
# Count: 8, Sum: 31, Min: 1, Max: 9三元(条件)表达式
score = 85
status = f"Result: {'PASS' if score >= 60 else 'FAIL'}"
print(status)
# Output: Result: PASS
temperature = -5
print(f"Water is {'frozen' if temperature <= 0 else 'liquid' if temperature < 100 else 'steam'}.")
# Output: Water is frozen.字典和列表访问
user = {"name": "Bob", "role": "engineer", "level": 3}
scores = [88, 92, 76, 95, 81]
print(f"{user['name']} is a level {user['level']} {user['role']}.")
# Output: Bob is a level 3 engineer.
print(f"First score: {scores[0]}, Last score: {scores[-1]}")
# Output: First score: 88, Last score: 81格式规范:数字、对齐和填充
F-strings 的真正威力体现在格式规范中。在表达式后添加冒号 :,后跟格式说明符。一般语法如下:
{expression:[[fill]align][sign][#][0][width][grouping_option][.precision][type]}这看起来很密集,但每个部分都是可选的。让我们通过示例来分解。
小数位和浮点精度
.Nf 说明符控制浮点数显示的小数位数:
pi = 3.141592653589793
print(f"Default: {pi}")
print(f"2 decimals: {pi:.2f}")
print(f"4 decimals: {pi:.4f}")
print(f"0 decimals: {pi:.0f}")
print(f"8 decimals: {pi:.8f}")
# Output:
# Default: 3.141592653589793
# 2 decimals: 3.14
# 4 decimals: 3.1416
# 0 decimals: 3
# 8 decimals: 3.14159265千位分隔符
使用逗号或下划线分组,大数字瞬间变得可读:
revenue = 1234567890
small_amount = 1234.5
print(f"Revenue: {revenue:,}")
print(f"Revenue: {revenue:_}")
print(f"Amount: ${small_amount:,.2f}")
# Output:
# Revenue: 1,234,567,890
# Revenue: 1_234_567_890
# Amount: $1,234.50百分比格式化
% 类型将值乘以 100 并附加百分号:
completion = 0.876
error_rate = 0.034
growth = 1.25
print(f"Completion: {completion:.1%}")
print(f"Error rate: {error_rate:.2%}")
print(f"Growth: {growth:.0%}")
# Output:
# Completion: 87.6%
# Error rate: 3.40%
# Growth: 125%科学计数法
avogadro = 6.022e23
planck = 6.626e-34
print(f"Avogadro: {avogadro:.3e}")
print(f"Planck: {planck:.4E}")
# Output:
# Avogadro: 6.022e+23
# Planck: 6.6260E-34整数进制:二进制、八进制、十六进制
value = 255
print(f"Decimal: {value:d}")
print(f"Binary: {value:b}")
print(f"Octal: {value:o}")
print(f"Hex (lower): {value:x}")
print(f"Hex (upper): {value:X}")
print(f"With prefix: {value:#b} {value:#o} {value:#x}")
# Output:
# Decimal: 255
# Binary: 11111111
# Octal: 377
# Hex (lower): ff
# Hex (upper): FF
# With prefix: 0b11111111 0o377 0xff对齐和填充
对齐说明符控制值在给定宽度内的位置。使用 < 表示左对齐,> 表示右对齐,^ 表示居中:
label = "Python"
print(f"|{label:<20}|") # Left-align in 20 chars
print(f"|{label:>20}|") # Right-align
print(f"|{label:^20}|") # Center
print(f"|{label:*^20}|") # Center with * fill
print(f"|{label:->20}|") # Right with - fill
# Output:
# |Python |
# | Python|
# | Python |
# |*******Python*******|
# |--------------Python|数字的零填充在报告格式化中很常见:
for i in [1, 42, 100, 7, 999]:
print(f"ID: {i:05d}")
# Output:
# ID: 00001
# ID: 00042
# ID: 00100
# ID: 00007
# ID: 00999构建对齐的表格
将对齐与格式规范结合,可以生成整洁的表格:
products = [
("Laptop Pro", 1299.99, 45),
("Wireless Mouse", 29.50, 230),
("USB-C Hub", 54.95, 120),
("Monitor 27in", 449.00, 67),
]
print(f"{'Product':<18} {'Price':>10} {'Stock':>7}")
print("-" * 37)
for name, price, stock in products:
print(f"{name:<18} ${price:>9.2f} {stock:>7,}")
print("-" * 37)
total_value = sum(p * s for _, p, s in products)
print(f"{'Total Value':<18} ${total_value:>9,.2f}")
# Output:
# Product Price Stock
# -------------------------------------
# Laptop Pro $ 1,299.99 45
# Wireless Mouse $ 29.50 230
# USB-C Hub $ 54.95 120
# Monitor 27in $ 449.00 67
# -------------------------------------
# Total Value $91,498.05使用 F-Strings 进行日期和时间格式化
F-strings 直接接受 strftime 格式代码,这意味着你可以格式化 datetime 对象而无需调用 .strftime():
from datetime import datetime, date, timedelta
now = datetime.now()
print(f"ISO format: {now:%Y-%m-%d %H:%M:%S}")
print(f"US format: {now:%m/%d/%Y}")
print(f"Long format: {now:%B %d, %Y at %I:%M %p}")
print(f"Day of week: {now:%A}")
print(f"Short month: {now:%b %d}")
# Output (varies by current time):
# ISO format: 2026-02-13 14:30:00
# US format: 02/13/2026
# Long format: February 13, 2026 at 02:30 PM
# Day of week: Friday
# Short month: Feb 13这也适用于 date 对象:
from datetime import date
birthday = date(1995, 8, 15)
today = date.today()
age_days = (today - birthday).days
print(f"Birthday: {birthday:%B %d, %Y}")
print(f"Days alive: {age_days:,}")
print(f"Years (approx): {age_days / 365.25:.1f}")
# Output:
# Birthday: August 15, 1995
# Days alive: 11,139
# Years (approx): 30.5多行 F-Strings
三引号 f-strings 允许你构建格式化的文本块。三引号 f-strings 中的每一行都可以包含 {} 表达式:
project = "Data Pipeline"
owner = "Engineering Team"
status = "In Progress"
completion = 0.73
budget = 250000
spent = 182500
report = f"""
========================================
Project Status Report
========================================
Project: {project}
Owner: {owner}
Status: {status}
Completion: {completion:.0%}
Budget: ${budget:>12,}
Spent: ${spent:>12,}
Remaining: ${budget - spent:>12,}
========================================
"""
print(report)你也可以通过隐式字符串拼接(将它们相邻放置,不使用运算符)将多个 f-strings 连接起来,构建多行 f-strings:
name = "Alice"
role = "Data Scientist"
years = 5
bio = (
f"Name: {name}\n"
f"Role: {role}\n"
f"Experience: {years} years\n"
f"Seniority: {'Senior' if years >= 5 else 'Mid-level'}"
)
print(bio)
# Output:
# Name: Alice
# Role: Data Scientist
# Experience: 5 years
# Seniority: Senior第二种方法避免了有时伴随三引号字符串的前导换行符和缩进问题。
用于调试的 = 说明符(Python 3.8+)
Python 3.8 为 f-strings 添加了 = 说明符,它是该语言中最有用的调试功能之一。当你编写 f"{expression=}" 时,Python 会同时打印表达式文本及其值。
x = 42
y = 17
print(f"{x=}")
print(f"{y=}")
print(f"{x + y=}")
print(f"{x * y=}")
# Output:
# x=42
# y=17
# x + y=59
# x * y=714你可以将 = 与格式说明符结合使用:
price = 49.99
tax_rate = 0.0825
total = price * (1 + tax_rate)
print(f"{price=:.2f}")
print(f"{tax_rate=:.1%}")
print(f"{total=:.2f}")
# Output:
# price=49.99
# tax_rate=8.2%
# total=54.12= 说明符会保留其周围的空白。在 = 前添加空格可以格式化输出:
name = "Alice"
score = 95
print(f"{name = }")
print(f"{score = }")
# Output:
# name = 'Alice'
# score = 95注意,对于字符串,= 默认使用 repr()(显示引号)。对于数字,它使用 str()。
调试复杂表达式
= 说明符适用于任何表达式,使其成为检查中间值的快速方法:
data = [23, 45, 12, 67, 34, 89, 56]
print(f"{len(data)=}")
print(f"{sum(data)=}")
print(f"{sum(data)/len(data)=:.2f}")
print(f"{sorted(data)=}")
print(f"{max(data) - min(data)=}")
# Output:
# len(data)=7
# sum(data)=326
# sum(data)/len(data)=46.57
# sorted(data)=[12, 23, 34, 45, 56, 67, 89]
# max(data) - min(data)=77如果你在 Jupyter 笔记本中工作,发现自己不断添加 print(f"{variable=}") 调用来调试,可以考虑 RunCell (opens in a new tab),这是一个直接在 Jupyter 内部运行的 AI 代理。RunCell 理解笔记本内存中的变量,可以检查、解释和提出修复建议,而无需你手动编写调试语句。它在逐步执行数据转换时特别有用,当你需要验证跨多个单元格的中间值时。
嵌套 F-Strings
你可以将 f-strings 嵌套在 f-strings 内部。最常见的用例是动态格式规范,其中宽度或精度来自变量:
# Dynamic precision
value = 3.14159265
for precision in range(1, 6):
print(f" {precision} decimals: {value:.{precision}f}")
# Output:
# 1 decimals: 3.1
# 2 decimals: 3.14
# 3 decimals: 3.142
# 4 decimals: 3.1416
# 5 decimals: 3.14159# Dynamic width
header = "Report"
for width in [20, 30, 40]:
print(f"|{header:^{width}}|")
# Output:
# | Report |
# | Report |
# | Report |# Nested f-string for formatting a list
values = [1.234, 56.789, 0.001, 999.999]
decimals = 2
formatted = f"Results: {', '.join(f'{v:.{decimals}f}' for v in values)}"
print(formatted)
# Output: Results: 1.23, 56.79, 0.00, 1000.00适度使用嵌套。如果 f-string 需要超过一层的嵌套,为了可读性,将内部逻辑提取到变量或函数中。
F-Strings 与其他字符串格式化方法对比
Python 有四种主要的字符串格式化方法。以下是直接对比:
| 特性 | f-string f"...{x}..." | .format() "...{}...".format(x) | % 运算符 "...%s..." % x | Template Template("...$x...") |
|---|---|---|---|---|
| Python 版本 | 3.6+ | 2.6+ | 所有版本 | 所有版本 |
| 可读性 | 优秀——值内联 | 良好——编号/命名占位符 | 一般——位置代码 | 良好——命名占位符 |
| 性能 | 最快 | 慢约 1.5-2 倍 | 慢约 1.3-1.8 倍 | 最慢 |
| 任意表达式 | 支持 | 有限 | 不支持 | 不支持 |
| 调试说明符 (=) | 支持 (3.8+) | 不支持 | 不支持 | 不支持 |
| 可复用模板 | 不支持 | 支持 | 支持 | 支持 |
| 用户输入安全 | 不安全 | 不安全 | 不安全 | 安全 (safe_substitute) |
| 类型格式化 | 完整 | 完整 | 部分 | 无 |
name = "Charlie"
balance = 1234.56
# f-string (recommended)
print(f"{name} has ${balance:,.2f}")
# .format()
print("{} has ${:,.2f}".format(name, balance))
# % formatting
print("%s has $%,.2f" % (name, balance)) # Note: % does not support comma grouping
# Template (from string module)
from string import Template
t = Template("$name has $balance")
print(t.substitute(name=name, balance=f"${balance:,.2f}"))何时使用每种方法:
- F-strings:新代码的默认选择。只要运行 Python 3.6+ 就使用它。
.format():当你需要将可复用模板存储在变量或配置文件中时使用。%格式化:仅用于遗留代码。新项目没有理由使用它。Template:当格式字符串来自不受信任的用户输入时使用(它不能执行任意表达式)。
性能对比
F-strings 更快,因为 Python 在解析时将它们编译为优化的字节码,避免了 .format() 和 % 所需的方法调用和参数解析开销。
import timeit
name = "Alice"
age = 30
score = 95.5
# Benchmark each method with 1 million iterations
fstring_time = timeit.timeit(
'f"{name} scored {score:.1f} at age {age}"',
globals={"name": name, "age": age, "score": score},
number=1_000_000
)
format_time = timeit.timeit(
'"{} scored {:.1f} at age {}".format(name, score, age)',
globals={"name": name, "age": age, "score": score},
number=1_000_000
)
percent_time = timeit.timeit(
'"%s scored %.1f at age %d" % (name, score, age)',
globals={"name": name, "age": age, "score": score},
number=1_000_000
)
concat_time = timeit.timeit(
'name + " scored " + str(score) + " at age " + str(age)',
globals={"name": name, "age": age, "score": score},
number=1_000_000
)
print(f"f-string: {fstring_time:.4f}s (baseline)")
print(f"str.format(): {format_time:.4f}s ({format_time/fstring_time:.2f}x slower)")
print(f"% formatting: {percent_time:.4f}s ({percent_time/fstring_time:.2f}x slower)")
print(f"concatenation: {concat_time:.4f}s ({concat_time/fstring_time:.2f}x slower)")
# Typical results:
# f-string: 0.0850s (baseline)
# str.format(): 0.1450s (1.71x slower)
# % formatting: 0.1100s (1.29x slower)
# concatenation: 0.1200s (1.41x slower)随着表达式变得更复杂,性能差距会扩大。在处理数千条记录的紧密循环中,f-strings 能产生可测量的差异。
常见错误和注意事项
转义花括号
要在 f-string 中包含字面量 { 或 },请将其加倍:
value = 42
# Literal braces around a value
print(f"{{{value}}}")
# Output: {42}
# JSON-like output
key = "name"
val = "Alice"
print(f'{{"{key}": "{val}"}}')
# Output: {"name": "Alice"}
# Just literal braces, no interpolation
print(f"Use {{variable}} syntax in f-strings")
# Output: Use {variable} syntax in f-strings表达式内部的反斜杠
你不能在 f-string 的 {} 表达式部分使用反斜杠字符。这是为了可读性而做出的有意设计选择:
items = ["apple", "banana", "cherry"]
# This causes a SyntaxError:
# print(f"{'\\n'.join(items)}")
# Solution 1: assign to a variable first
newline = "\n"
print(f"{newline.join(items)}")
# Solution 2: use a separate operation
joined = "\n".join(items)
print(f"Items:\n{joined}")
# Solution 3: use chr()
print(f"{chr(10).join(items)}")引号冲突
当 f-string 使用双引号时,内部表达式必须使用单引号(或反之亦然):
data = {"name": "Alice", "age": 30}
# Use single quotes inside when f-string uses double quotes
print(f"Name: {data['name']}, Age: {data['age']}")
# Or use double quotes inside when f-string uses single quotes
print(f'Name: {data["name"]}, Age: {data["age"]}')
# With triple quotes, you have more flexibility
print(f"""Name: {data["name"]}, Age: {data["age"]}""")F-Strings 不是常量
F-strings 在运行时计算,这意味着你不能将它们用作依赖运行时状态的默认参数值或模块级常量:
# This works but evaluates at call time, not definition time
def greet(name, template=None):
if template is None:
template = f"Hello, {name}!" # Evaluated here
return template
# For true templates, use str.format()
TEMPLATE = "Hello, {name}! You have {count} messages."
print(TEMPLATE.format(name="Alice", count=5))注意大型表达式
仅仅因为你可以在 f-string 中放入任何表达式,并不意味着你应该这样做。保持 f-string 表达式简单:
# Hard to read -- too much logic inside the f-string
result = f"{'%.2f' % (sum(x**2 for x in range(100)) / 100)}"
# Much better -- compute first, then format
mean_square = sum(x**2 for x in range(100)) / 100
result = f"{mean_square:.2f}"原始 F-Strings
组合 r(原始)和 f 前缀会创建一个原始 f-string,其中反斜杠按字面意义处理(无转义序列),同时表达式仍然会被计算:
user = "admin"
folder = "projects"
# Raw f-string for Windows paths
path = rf"C:\Users\{user}\{folder}\data.csv"
print(path)
# Output: C:\Users\admin\projects\data.csv
# Useful for regex patterns with dynamic parts
import re
prefix = "user"
pattern = rf"\b{prefix}_\d+\b"
text = "Found user_123 and user_456 in the log"
matches = re.findall(pattern, text)
print(f"Matches: {matches}")
# Output: Matches: ['user_123', 'user_456']rf"..." 和 fr"..." 都是有效的——前缀的顺序无关紧要。
数据科学工作流程中的 F-Strings
F-strings 在数据科学中对于格式化输出、构建动态标签以及从数值结果创建可读的摘要非常宝贵。
格式化数值输出
import statistics
data = [23.4, 45.1, 31.8, 52.3, 41.7, 38.9, 29.6, 47.2]
mean = statistics.mean(data)
median = statistics.median(data)
stdev = statistics.stdev(data)
cv = stdev / mean # coefficient of variation
print(f"Sample size: {len(data)}")
print(f"Mean: {mean:.2f}")
print(f"Median: {median:.2f}")
print(f"Std deviation: {stdev:.2f}")
print(f"CV: {cv:.1%}")
print(f"Range: {min(data):.1f} - {max(data):.1f}")
# Output:
# Sample size: 8
# Mean: 38.75
# Median: 40.30
# Std deviation: 9.87
# CV: 25.5%
# Range: 23.4 - 52.3使用 Pandas DataFrames
import pandas as pd
df = pd.DataFrame({
"product": ["Widget A", "Widget B", "Widget C", "Widget D"],
"revenue": [125000, 89000, 234000, 67000],
"units": [1250, 2100, 980, 3400],
})
# Summary statistics with f-strings
total_rev = df["revenue"].sum()
avg_price = (df["revenue"] / df["units"]).mean()
print(f"Total Revenue: ${total_rev:>12,}")
print(f"Avg Unit Price: ${avg_price:>12,.2f}")
print(f"Products: {len(df):>12,}")
# Dynamic column formatting
for _, row in df.iterrows():
unit_price = row["revenue"] / row["units"]
print(f" {row['product']:<12} | Revenue: ${row['revenue']:>9,} | Units: {row['units']:>5,} | $/unit: ${unit_price:.2f}")
# Output:
# Total Revenue: $ 515,000
# Avg Unit Price: $ 56.00
# Products: 4
# Widget A | Revenue: $ 125,000 | Units: 1,250 | $/unit: $100.00
# Widget B | Revenue: $ 89,000 | Units: 2,100 | $/unit: $42.38
# Widget C | Revenue: $ 234,000 | Units: 980 | $/unit: $238.78
# Widget D | Revenue: $ 67,000 | Units: 3,400 | $/unit: $19.71当你的数据分析超越文本摘要,需要交互式探索时,PyGWalker (opens in a new tab) 可以通过单行代码将任何 pandas DataFrame 转换为类似 Tableau 的交互式可视化。你无需手动格式化数字生成静态报告,而是可以拖放列来构建图表、应用过滤器并直观地探索模式——全部在你的 Jupyter 笔记本中完成。
import pandas as pd
import pygwalker as pyg
# After preparing your DataFrame with well-formatted columns
df = pd.DataFrame({
"Month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
"Revenue": [125000, 134000, 158000, 142000, 167000, 189000],
"Growth": [0.05, 0.072, 0.179, -0.101, 0.176, 0.132],
})
# Add formatted columns for display
df["Revenue_Display"] = df["Revenue"].apply(lambda x: f"${x:,.0f}")
df["Growth_Display"] = df["Growth"].apply(lambda x: f"{x:+.1%}")
# Launch interactive visualization
# pyg.walk(df)格式化模型结果
# Formatting machine learning results
metrics = {
"accuracy": 0.9234,
"precision": 0.8891,
"recall": 0.9456,
"f1_score": 0.9164,
"auc_roc": 0.9678,
}
print("Model Evaluation Results")
print("=" * 35)
for metric, value in metrics.items():
bar_length = int(value * 20)
bar = "#" * bar_length + "-" * (20 - bar_length)
print(f" {metric:<12} {value:.4f} [{bar}]")
# Output:
# Model Evaluation Results
# ===================================
# accuracy 0.9234 [##################--]
# precision 0.8891 [#################---]
# recall 0.9456 [##################--]
# f1_score 0.9164 [##################--]
# auc_roc 0.9678 [###################-]转换标志:!s、!r 和 !a
F-strings 支持三种转换标志,控制表达式值在格式化前的转换方式:
!s对值调用str()(默认行为)!r对值调用repr()!a对值调用ascii()
text = "Hello\tWorld"
name = "Caf\u00e9"
print(f"str: {text!s}")
print(f"repr: {text!r}")
print(f"ascii: {name!a}")
# Output:
# str: Hello World
# repr: 'Hello\tWorld'
# ascii: 'Caf\xe9'!r 标志对调试特别有用,因为它显示原始表示,包括引号和转义字符。它与 = 说明符配合得很好。
常见问题
什么是 Python f-strings,它们何时引入的?
F-strings(格式化字符串字面值)是通过 PEP 498 在 Python 3.6 中引入的一种字符串格式化机制。它们允许你通过在字符串前加上 f 并将表达式放入花括号内,直接将 Python 表达式嵌入字符串字面值中。F-strings 在运行时计算,在所有格式化选项中提供最佳的可读性,并且比 str.format() 和 % 格式化更快,因为它们在解析时编译为优化的字节码。
如何在 f-strings 中使用逗号和十进制位格式化数字?
在花括号内使用冒号后的格式规范。对于千位分隔符逗号,使用 , —— 例如,f"{1234567:,}" 产生 "1,234,567"。对于小数位,使用 :.Nf,其中 N 是位数 —— 例如,f"{3.14159:.2f}" 得到 "3.14"。两者结合:f"{1234.5:,.2f}" 输出 "1,234.50"。对于百分比,使用 :.N%,它将值乘以 100 并附加百分号:f"{0.85:.1%}" 产生 "85.0%"。
f-string 的 = 说明符是什么,它如何帮助调试?
= 说明符在 Python 3.8 中添加,它会同时打印表达式文本及其值。编写 f"{variable=}" 会输出 variable=value。这消除了在调试时两次输入变量名的需要。它适用于任何表达式:f"{len(data)=}" 输出 len(data)=42。你可以将它与格式规范结合使用:f"{price=:.2f}" 输出 price=49.99。这是检查中间值的最快方法之一。
我可以在多行字符串中使用 f-strings 吗?
可以。使用三引号(f"""...""" 或 f'''...''')表示多行 f-strings。每一行都可以包含 {expression} 占位符。或者,你可以通过将多个 f-strings 相邻放置在括号中使用隐式字符串拼接来连接它们。
F-strings 比 str.format() 和 % 格式化更快吗?
是的。F-strings 始终是 Python 中最快的字符串格式化方法。在基准测试中,f-strings 通常比 str.format() 快 1.5 到 2 倍,比 % 格式化快 1.3 到 1.8 倍。速度优势来自编译时优化,Python 将 f-strings 直接转换为高效的机器码。
如何在 f-string 中包含字面量花括号?
将花括号加倍。使用 {{ 表示字面量 {,}} 表示字面量 }。例如,f"{{value}}" 输出 {value} 作为纯文本。要将插值后的值包裹在花括号中,使用 f"{{{variable}}}" —— 外部加倍的花括号产生字面量花括号,而内部的单花括号触发插值。
结论
F-strings 是现代 Python 中格式化字符串的标准方式。它们结合了任何格式化方法中最佳的可读性和最佳的性能,并且支持完整的格式规范范围:小数精度、千位分隔符、百分比、科学计数法、对齐、填充、日期格式化和进制转换。
需要记住的关键点:
- 使用
f作为前缀,将表达式放入{花括号}内。 - 使用
:后跟格式规范进行精确输出控制(:.2f、:,、:.1%、:<20)。 - 在表达式后使用
=进行调试(f"{variable=}")。需要 Python 3.8+。 - 通过加倍转义字面量花括号:
{{和}}。 - 不要在
{}表达式内部放置反斜杠。先赋值给变量。 - 保持表达式简单。如果
{}内的逻辑难以阅读,请将其提取出来。 - 仅在需要将可复用模板存储为变量时使用
.format()。
F-strings 处理从快速的 print() 调试到生产报告生成的所有内容。一旦你采用了它们,就没有理由回到旧的格式化方法。无论你是在构建数据管道、格式化 ML 模型输出,还是生成财务报告,f-strings 都能提供简洁、快速、可读的代码。