01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
01-【Python-Day 1】告别编程恐惧:轻松掌握 Python 安装与第一个程序的 6 个步骤
02-【Python-Day 2】掌握Python基石:变量、内存、标识符及int/float/bool数据类型
03-【Python-Day 3】玩转文本:字符串(String)基础操作详解 (上)
04-【Python-Day 4】玩转文本:Python 字符串常用方法深度解析 (下篇)
05-【Python-Day 5】Python 格式化输出实战:%、format()、f-string 对比与最佳实践
大家好,欢迎来到 Python 学习之旅的第五天!在前几天的学习中,我们掌握了 Python 的基础语法、变量、数据类型以及强大的字符串操作。然而,仅仅能够处理和操作字符串是不够的,如何将这些数据以清晰、美观、专业的方式展示出来,同样至关重要。想象一下,如果你需要打印一份报告、生成一段日志或者向用户显示一条信息,杂乱无章的输出会大大降低可读性。本篇文章将聚焦于 Python 中的字符串格式化技术,教你如何优雅地控制输出格式,让你的打印内容焕然一新!我们将从经典的 %
格式化讲起,逐步过渡到功能更强大的 str.format()
方法,最后重点介绍 Python 3.6+ 版本中备受推崇的 f-string。同时,我们还会深入探讨常用的格式控制符,如对齐、精度和类型转换,助你彻底掌握格式化输出的精髓。
在正式学习格式化方法之前,我们先来思考一个问题:为什么 Python 内置了 print()
函数还不够,我们还需要专门学习字符串格式化呢?
使用基本的 print()
函数和字符串拼接(+
)虽然也能组合输出,但在处理多个变量或不同数据类型时,代码会显得非常冗长和混乱,而且容易出错。
示例:
name = "Alice"
age = 30
city = "New York"
# 使用 + 拼接,需要手动转换非字符串类型
print("User Info: Name: " + name + ", Age: " + str(age) + ", City: " + city)
# 输出: User Info: Name: Alice, Age: 30, City: New York
# 如果变量很多,拼接会变得非常复杂且难以阅读
score = 95.5
is_active = True
print("Detail: " + name + " scored " + str(score) + " and is currently " + ("active" if is_active else "inactive") + ".")
# 输出: Detail: Alice scored 95.5 and is currently active.
从上面的例子可以看出,简单的拼接不仅代码可读性差,还需要频繁使用 str()
进行类型转换,非常不便。
字符串格式化提供了一种更优雅、更强大、更易读的方式来构建包含变量的字符串。其主要优势包括:
接下来,我们将详细介绍 Python 中三种主要的字符串格式化方法。
Python 提供了多种方式来进行字符串格式化,主要有以下三种:
%
格式化: 源自 C 语言的 printf
风格,历史悠久。str.format()
方法: Python 2.6 引入,功能更强大、更灵活。这种方式使用 %
操作符连接一个模板字符串和一个或多个值(通常放在元组或字典中)。模板字符串中使用 %
加上特定的转换说明符(如 %s
表示字符串,%d
表示整数,%f
表示浮点数)作为占位符。
语法: template_string % values
示例:
name = "Bob"
age = 25
height = 1.75
# 使用元组传递值
formatted_string_tuple = "Name: %s, Age: %d, Height: %.2f meters" % (name, age, height)
print(formatted_string_tuple)
# 输出: Name: Bob, Age: 25, Height: 1.75 meters
# 使用字典传递值 (通过名称引用)
user_data = {"user_name": "Charlie", "user_age": 40}
formatted_string_dict = "User: %(user_name)s, Age: %(user_age)d" % user_data
print(formatted_string_dict)
# 输出: User: Charlie, Age: 40
说明符 | 转换 | 示例 |
---|---|---|
%s |
字符串 (或任何对象,会调用 str() ) |
'Hello' |
%d |
十进制整数 | 123 |
%f |
浮点数 (默认保留 6 位小数) | 3.141593 |
%.nf |
浮点数 (保留 n 位小数) | %.2f -> 3.14 |
%e |
科学计数法 (小写 ‘e’) | 3.14e+00 |
%E |
科学计数法 (大写 ‘E’) | 3.14E+00 |
%g |
根据值自动选择 %f 或 %e |
|
%G |
根据值自动选择 %f 或 %E |
|
%% |
输出一个 % 字符 |
% |
%d
格式化字符串)会直接报错 TypeError
。由于这些缺点,不推荐在新的 Python 代码中使用 %
格式化,但了解它有助于阅读旧代码。
str.format()
方法为了克服 %
格式化的不足,Python 2.6 引入了 str.format()
方法。它使用花括号 {}
作为占位符,并通过 format()
方法传入要替换的值。
语法: template_string.format(value1, value2, ...)
或 template_string.format(key1=value1, key2=value2, ...)
示例:
name = "David"
age = 35
pi = 3.1415926
# 按位置顺序填充
formatted_pos = "Name: {}, Age: {}, Pi: {}".format(name, age, pi)
print(formatted_pos)
# 输出: Name: David, Age: 35, Pi: 3.1415926
# 按索引填充 (可以改变顺序或重复使用)
formatted_idx = "Age: {1}, Name: {0}, Age again: {1}".format(name, age)
print(formatted_idx)
# 输出: Age: 35, Name: David, Age again: 35
# 按关键字填充 (更易读)
formatted_kw = "User {username} is {userage} years old.".format(username="Eve", userage=28)
print(formatted_kw)
# 输出: User Eve is 28 years old.
# 混合使用 (位置参数必须在前)
formatted_mix = "Name: {}, Age: {age}".format(name, age=age)
print(formatted_mix)
# 输出: Name: David, Age: 35
# 访问对象的属性或字典的键
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(10, 20)
data = {"city": "London", "country": "UK"}
formatted_attr = "Point coordinates: ({p.x}, {p.y})".format(p=p)
print(formatted_attr)
# 输出: Point coordinates: (10, 20)
formatted_dict_key = "Location: {d[city]}, {d[country]}".format(d=data)
print(formatted_dict_key)
# 输出: Location: London, UK
str.format()
的强大之处在于花括号 {}
内部可以包含格式规范迷你语言 (Format Specification Mini-Language),用来精确控制输出格式。基本语法是 {:[[fill]align][sign][#][0][width][,][.precision][type]}
。我们将在第三部分详细讲解常用的控制符。
简单示例:
pi = 3.1415926
# 控制小数位数
formatted_precision = "Pi approximation: {:.2f}".format(pi)
print(formatted_precision)
# 输出: Pi approximation: 3.14
# 控制宽度和对齐
name = "Alice"
formatted_align = "Name: {:>10}".format(name) # 右对齐,总宽度10
print(formatted_align)
# 输出: Name: Alice
%
格式化更易读,特别是使用关键字参数时。str.format()
是一个功能完备且兼容性好的选择(兼容 Python 2.6+ 和 3.x)。
f-string(格式化字符串字面值)是 Python 3.6 引入的新特性,旨在提供一种更简洁、更直观、性能也通常更好的字符串格式化方式。
f-string 的语法非常简单:在字符串字面量前面加上字母 f
或 F
,然后在花括号 {}
内直接写入变量名或表达式。
语法: f"text {variable} text {expression} text"
name = "Frank"
age = 42
pi = 3.1415926
formatted_fstring = f"User {name} is {age} years old. Pi is approximately {pi}."
print(formatted_fstring)
# 输出: User Frank is 42 years old. Pi is approximately 3.1415926.
可以看到,代码非常简洁,变量直接嵌入字符串中,可读性极高。
f-string 的花括号内不仅可以放变量,还可以放任何有效的 Python 表达式。
x = 10
y = 5
formatted_expr = f"Sum: {x + y}, Product: {x * y}, Is x > y? {x > y}"
print(formatted_expr)
# 输出: Sum: 15, Product: 50, Is x > y? True
# 也可以调用函数
def greet(name):
return f"Hello, {name.capitalize()}!"
formatted_func = f"{greet('grace')}"
print(formatted_func)
# 输出: Hello, Grace!
str.format()
和 %
格式化更快,因为它们在编译时处理。str.format()
相同的格式规范迷你语言。强烈推荐在 Python 3.6 及以上版本中使用 f-string 进行字符串格式化。
无论是 str.format()
还是 f-string,它们都支持一套强大的格式规范迷你语言 (Format Specification Mini-Language) 来控制输出的细节。格式规范位于花括号 {}
内,紧跟在变量名或表达式之后,并以冒号 :
分隔。
基本结构::[[fill]align][sign][#][0][width][,][.precision][type]
我们重点关注其中最常用的几个部分:对齐、精度和类型。
用于控制字符串在给定宽度内的对齐方式。需要配合 width
(最小总宽度)使用。
对齐符 | 含义 | 示例 (width=10) |
---|---|---|
< |
左对齐 | f"{'text':<10}" -> text |
> |
右对齐 | f"{'text':>10}" -> text |
^ |
居中对齐 | f"{'text':^10}" -> text |
<
)name = "Leo"
width = 10
# 使用 format()
print("'{0:<{1}}'".format(name, width)) # '{0:<10}'.format(name)
# 使用 f-string
print(f"'{name:<{width}}'") # f"'{name:<10}'"
# 输出:
# 'Leo '
# 'Leo '
>
)name = "Mia"
width = 10
# 使用 format()
print("'{0:>{1}}'".format(name, width))
# 使用 f-string
print(f"'{name:>{width}}'")
# 输出:
# ' Mia'
# ' Mia'
^
)name = "Noah"
width = 10
# 使用 format()
print("'{0:^{1}}'".format(name, width))
# 使用 f-string
print(f"'{name:^{width}}'")
# 输出:
# ' Noah '
# ' Noah '
可以在对齐符号前指定一个字符用于填充空白区域(默认为空格)。
name = "Zoe"
width = 10
fill_char = '*'
# 使用 format()
print("'{0:*^{1}}'".format(name, width)) # 居中对齐,用 * 填充
# 使用 f-string
print(f"'{name:*^{width}}'") # 同上
# 输出:
# '***Zoe****'
# '***Zoe****'
# 右对齐,用 0 填充(常用于数字)
num = 123
print(f"{num:0>8}") # 注意,对于数字,0 有特殊含义(见下文),但这里放在 > 前,表示填充
# 输出: 00000123
注意: 如果指定了 0
作为格式说明符的一部分(如 08d
),它表示用 0 填充 并且 应用于数字类型,此时它通常结合宽度使用,不需要显式指定对齐(默认右对齐)。如 f"{num:08d}"
效果同 f"{num:0>8d}"
。
主要用于控制浮点数的小数位数或字符串的最大显示宽度。用点号 .
后跟一个整数表示。
.nf
)指定浮点数输出时保留的小数位数 n
。会进行四舍五入。
pi = 3.1415926535
# 使用 format()
print("Pi: {:.3f}".format(pi)) # 保留 3 位小数
# 使用 f-string
print(f"Pi: {pi:.3f}") # 同上
# 输出:
# Pi: 3.142
# Pi: 3.142
# 结合宽度和对齐
print(f"'{pi:10.2f}'") # 总宽度 10,保留 2 位小数,默认右对齐
# 输出: ' 3.14'
.ns
)指定字符串输出时的最大字符数 n
。如果原字符串超过此长度,会被截断。
long_text = "This is a very long string."
max_width = 10
# 使用 format()
print("'{:.{}}'".format(long_text, max_width)) # '{:.10}'.format(long_text)
# 使用 f-string
print(f"'{long_text:.{max_width}}'") # f"'{long_text:.10}'"
# 输出:
# 'This is a '
# 'This is a '
指定变量应被视为哪种类型进行格式化。
s
)这是默认类型,通常可以省略。会将对象转换为字符串(调用 str()
)。
name = "Olivia"
age = 22
print(f"Name: {name:s}, Age: {age:s}") # :s 可以省略
# 输出: Name: Olivia, Age: 22
d
, b
, o
, x
, X
)d
: 十进制整数 (Decimal) - 默认整数类型b
: 二进制 (Binary)o
: 八进制 (Octal)x
: 十六进制 (Hexadecimal, 小写 a-f)X
: 十六进制 (Hexadecimal, 大写 A-F)num = 42
print(f"Decimal: {num:d}") # Decimal: 42
print(f"Binary: {num:b}") # Binary: 101010
print(f"Octal: {num:o}") # Octal: 52
print(f"Hex (lower): {num:x}") # Hex (lower): 2a
print(f"Hex (upper): {num:X}") # Hex (upper): 2A
# 带 # 前缀,显示进制标识 (0b, 0o, 0x)
print(f"Binary with prefix: {num:#b}") # Binary with prefix: 0b101010
print(f"Hex with prefix: {num:#x}") # Hex with prefix: 0x2a
f
, e
, E
, g
, G
, %
)f
: 定点表示法 (Fixed-point notation),默认 6 位小数。e
: 科学计数法 (Exponent notation),小写 ‘e’。E
: 科学计数法 (Exponent notation),大写 ‘E’。g
: 通用格式 (General format)。对于给定精度 p >= 1,它会格式化数字为定点表示法(如果指数在 -4 到 p-1 之间),否则格式化为科学计数法。默认精度为 6。G
: 通用格式 (General format),类似 g
,但在科学计数法时使用大写 ‘E’。%
: 百分比格式。将数字乘以 100,然后使用 f
格式显示,并附加一个 %
号。value = 12345.6789
ratio = 0.9876
print(f"Fixed point: {value:f}") # Fixed point: 12345.678900
print(f"Fixed point (2 dec): {value:.2f}") # Fixed point (2 dec): 12345.68
print(f"Exponent (lower): {value:e}") # Exponent (lower): 1.234568e+04
print(f"Exponent (upper): {value:E}") # Exponent (upper): 1.234568E+04
print(f"General (default): {value:g}") # General (default): 12345.7 (默认精度6)
print(f"General (precision 8): {value:.8g}") # General (precision 8): 12345.679
print(f"Percentage (1 dec): {ratio:.1%}") # Percentage (1 dec): 98.8%
我们可以将对齐、宽度、精度、类型等控制符组合使用。
item = "Apple"
price = 1.25
quantity = 10
# 目标:输出类似表格的一行
# | Item | Price | Quantity | Total |
# | :------- | -----: | -------: | -------: |
# | Apple | 1.25 | 10 | 12.50 |
header = f"| {'Item':<8} | {'Price':>6} | {'Quantity':>8} | {'Total':>8} |"
divider = "-" * len(header)
data_row = f"| {item:<8} | {price:>6.2f} | {quantity:>8d} | {price * quantity:>8.2f} |"
print(header)
print(divider)
print(data_row)
# 输出:
# | Item | Price | Quantity | Total |
# ---------------------------------------------
# | Apple | 1.25 | 10 | 12.50 |
字符串格式化在各种编程任务中都非常有用:
%
格式化类型不匹配: 使用 %
时,如果占位符类型与提供的变量类型不兼容(例如 %d
用于字符串),会抛出 TypeError
。format()
和 f-string 通常更宽容,会尝试调用 __format__()
或 str()
。str.format()
占位符与参数数量/名称不匹配:
IndexError
。format()
调用中缺少某个占位符所需的关键字,会抛出 KeyError
。SyntaxError
。如果需要兼容旧版本,应使用 str.format()
。{}
的转义: 如果想在格式化字符串中直接输出花括号本身,需要使用双花括号 {{
和 }}
。# 使用 format()
print("This shows curly braces: {{}}".format()) # 输出: This shows curly braces: {}
# 使用 f-string
value = 42
print(f"This includes a value {value} and literal braces {{}}")
# 输出: This includes a value 42 and literal braces {}
\
: 在 f-string 的表达式部分不能直接使用反斜杠 \
进行换行或转义(除非是字符串字面量内部)。# 错误示例:
# my_string = f"This is a long string \
# split across lines." # SyntaxError
# 正确做法 (在表达式外拆分或使用括号):
part1 = "This is a long string"
part2 = "split across lines."
my_string = f"{part1} {part2}"
print(my_string)
my_list = [1, 2, 3]
# 在表达式中使用括号可以换行
my_string_expr = f"List sum: {sum([
x*2 for x in my_list
])}"
print(my_string_expr)
str.format()
: 当需要兼容 Python 2.6-3.5 版本,或者在某些特定场景(如模板字符串来源不确定,需要延迟格式化)下,str.format()
是一个强大且可靠的选择。%
格式化 (新代码): 尽量不要在新的代码中使用 %
格式化,除非是在维护必须兼容非常古老 Python 版本的旧代码。今天我们深入学习了 Python 中让输出变得美观专业的关键技术——字符串格式化。核心要点回顾如下:
print()
和字符串拼接的局限性,提高了代码的可读性、简洁性和可维护性,并能精确控制输出样式。%
格式化: C printf
风格,语法简单但功能有限、可读性差,不推荐在新代码中使用。str.format()
: Python 2.6+ 引入,功能强大,支持位置/关键字参数、索引、属性访问,使用 {}
占位符和格式规范迷你语言,是兼容性好的选择。f
,直接在 {}
内嵌入变量和表达式,语法最简洁、可读性最好、性能通常最优,是现代 Python 的首选。:
后面的格式规范迷你语言中的核心部分:
<
, >
, ^
) 配合宽度和可选的填充字符。.n
) 控制浮点数小数位数或字符串最大长度。d
, s
, f
, e
, g
, %
, b
, o
, x
等) 指定数据如何被解释和显示。str.format()
,避免在新建项目中使用 %
格式化。熟练掌握字符串格式化,不仅能让你的程序输出更加专业,也能在调试和展示数据时提供极大的便利。希望通过今天的学习,你能自信地运用这些技巧美化你的 Python 输出!下一篇,我们将学习 Python 中的运算符,敬请期待!