在Python编程中,字符串格式化是一项基础且重要的技能。无论是简单的日志输出,还是复杂的数据展示,掌握好字符串格式化都能让代码更加优雅和高效。本文将深入浅出地介绍Python中各种字符串格式化方法,帮助你选择最适合的方案。
一、Python字符串格式化的演进历程
Python的字符串格式化经历了三个重要阶段:
-
Python 2:%-formatting(模仿C语言的printf)
-
Python 3.0:str.format() 方法
-
Python 3.6:f-strings(最现代的方式)
二、三种主要的格式化方式详解
1. %-formatting(传统方式)
这是Python最古老的字符串格式化方法,使用%操作符。
# 基本用法 name = "Alice" age = 25 print("My name is %s and I'm %d years old" % (name, age)) # 常用格式化符号 # %s - 字符串 # %d - 整数 # %f - 浮点数 # %x - 十六进制 # 格式化数字 pi = 3.14159 print("Pi is %.2f" % pi) # 保留两位小数:3.14 # 使用字典 data = {'name': 'Bob', 'age': 30} print("Name: %(name)s, Age: %(age)d" % data)
优点:简单直观,适合简单场景
缺点:类型限制严格,可读性差,容易出错
2. str.format() 方法(过渡方式)
Python 3.0引入,提供了更强大的功能。
# 基本用法 name = "Charlie" age = 35 print("My name is {} and I'm {} years old".format(name, age)) # 使用索引 print("My name is {0} and I'm {1} years old".format(name, age)) # 使用参数名 print("My name is {name} and I'm {age} years old".format(name=name, age=age)) # 格式化数字 pi = 3.14159 print("Pi is {:.2f}".format(pi)) # 3.14 # 对齐和填充 print("{:<10} is left aligned".format("Text")) # 左对齐 print("{:>10} is right aligned".format("Text")) # 右对齐 print("{:^10} is centered".format("Text")) # 居中 print("{:*^10}".format("Text")) # 居中使用*填充 # 千位分隔符 large_num = 1000000 print("{:,}".format(large_num)) # 1,000,000 # 日期格式化 from datetime import datetime now = datetime.now() print("{:%Y-%m-%d %H:%M}".format(now))
优点:功能强大,灵活性强
缺点:语法略显冗长
3. f-strings(推荐方式)
Python 3.6引入,是目前最推荐的格式化方式。
# 基本用法 name = "David" age = 40 print(f"My name is {name} and I'm {age} years old") # 表达式求值 a, b = 5, 3 print(f"{a} + {b} = {a + b}") print(f"{a} > {b} is {a > b}") # 调用函数 def greet(name): return f"Hello, {name}" print(f"Message: {greet('Eve')}") # 格式化数字 pi = 3.14159 print(f"Pi is {pi:.2f}") # 3.14 # 对齐和填充 text = "Python" print(f"{text:<10} left") print(f"{text:>10} right") print(f"{text:^10} center") # 字典访问 person = {'name': 'Frank', 'age': 45} print(f"{person['name']} is {person['age']} years old") # 调试功能(Python 3.8+) x = 42 print(f"{x = }") # 输出:x = 42 print(f"{x = :#x}") # 十六进制:x = 0x2a # 多行f-string name = "Grace" age = 28 message = ( f"Name: {name}\n" f"Age: {age}\n" f"Next year: {age + 1}" ) print(message)
优点:简洁、直观、性能好、支持表达式
缺点:只能在Python 3.6+使用
三、实战案例
1. 日志记录
import logging from datetime import datetime # 使用f-strings记录日志 def log_user_action(user_id, action, status): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_msg = f"[{timestamp}] User {user_id}: {action} - {status}" print(log_msg) # 实际项目中会使用logging模块 log_user_action(1001, "login", "success")
2. 数据报表生成
def generate_report(products): """生成商品销售报表""" print("=" * 50) print(f"{'Product':<20} {'Price':>10} {'Sold':>10} {'Total':>10}") print("=" * 50) total_revenue = 0 for product in products: total = product['price'] * product['sold'] total_revenue += total print(f"{product['name']:<20} ${product['price']:>9.2f} " f"{product['sold']:>10} ${total:>9.2f}") print("=" * 50) print(f"{'TOTAL REVENUE:':<40} ${total_revenue:>9.2f}") # 测试数据 products = [ {'name': 'Laptop', 'price': 999.99, 'sold': 5}, {'name': 'Mouse', 'price': 29.99, 'sold': 20}, {'name': 'Keyboard', 'price': 79.99, 'sold': 10} ] generate_report(products)
3. 进度条显示
import time def show_progress(iterations=50): """显示简单的进度条""" for i in range(iterations + 1): percent = (i / iterations) * 100 filled = int(i / iterations * 30) bar = "█" * filled + "░" * (30 - filled) print(f"\rProgress: |{bar}| {i}/{iterations} ({percent:.1f}%)", end="", flush=True) time.sleep(0.05) print() # 换行 show_progress()
四、性能对比
import timeit # 测试各种格式化方法的性能 name = "Python" version = 3.9 def test_percent(): return "Hello %s, version %.1f" % (name, version) def test_format(): return "Hello {}, version {:.1f}".format(name, version) def test_fstring(): return f"Hello {name}, version {version:.1f}" # 执行性能测试 percent_time = timeit.timeit(test_percent, number=1000000) format_time = timeit.timeit(test_format, number=1000000) fstring_time = timeit.timeit(test_fstring, number=1000000) print(f"%-formatting: {percent_time:.4f} seconds") print(f"str.format(): {format_time:.4f} seconds") print(f"f-strings: {fstring_time:.4f} seconds")
五、最佳实践建议
✅ 推荐的做法
-
优先使用f-strings(Python 3.6+)
# 好的做法 name = "Alice" print(f"Hello, {name}")
-
复杂格式化使用str.format()
# 当需要重复使用模板时 template = "Hello, {name}. You are {age} years old." print(template.format(name="Bob", age=25))
-
多行字符串处理
# 使括号组织多行 query = ( f"SELECT * FROM users " f"WHERE age > {min_age} " f"ORDER BY name" )
❌ 需要避免的做法
-
避免过于复杂的表达式
# 不推荐 print(f"Result: {[x**2 for x in range(10) if x % 2 == 0]}") # 推荐 even_squares = [x**2 for x in range(10) if x % 2 == 0] print(f"Result: {even_squares}")
-
避免在日志中使用f-strings
import logging # 不推荐 logging.error(f"Error: {error_msg}") # 即使日志级别不匹配也会执行 # 推荐 logging.error("Error: %s", error_msg) # 延迟格式化,提升性能
六、常见问题解答
Q1: f-strings和str.format()哪个更快?
A: f-strings通常更快,因为它在编译时就确定了格式,而不是运行时解析。
Q2: 如何在f-string中使用大括号?
# 使用双大括号 print(f"{{}} 是字典的表示") # 输出:{} 是字典的表示
Q3: f-string可以嵌套吗?
# f-string嵌套 width = 10 text = "Python" print(f"{text:>{width}}") # 右对齐,宽度10
总结
选择合适的字符串格式化方法:
-
如果使用Python 3.6+,优先选择f-strings
-
需要兼容旧版本Python时,使用str.format()
-
简单的字符串拼接,可以使用+
-
日志记录等场景,使用%-formatting延迟格式化
掌握这些技巧,相信你的Python代码会更加简洁、高效和易读。记住,选择什么方法取决于具体场景,没有绝对的”最好”,只有”最合适”。