数据处理与序列化|第七部分:Python标准库精选 (The Standard Library)
欢迎来到数据处理的核心地带!在真实的软件世界里,数据很少是简单的数字和字符串。它们通常以特定的格式存在:日志文件中的时间戳、网页上的复杂文本、API返回的JSON对象等等。要成为一名高效的开发者,你必须能够熟练地解析、操作和转换这些数据。
本章,我们将聚焦于Python标准库中三个用于数据处理的“超级英雄”模块:
datetime
: 你的“时间机器”,让你能够轻松地处理日期、时间、时区,并进行各种时间计算。re
(正则表达式): 文本处理的“终极武器”。它能让你定义复杂的匹配模式,从海量文本中精准地查找、提取和替换你需要的信息。json
: 现代网络世界的“通用语”。我们将学习如何将Python对象与JSON格式进行无缝转换,这是编写任何网络应用(Web开发、API交互、爬虫等)的必备技能。
此外,我们还会简要介绍 pickle
和 xml
,它们分别用于处理Python专属的对象序列化和传统的XML数据格式。掌握这些工具,你将能自如地应对绝大多数数据处理挑战。
17.1 datetime
模块:掌控时间
在编程中,处理时间远比想象的复杂,涉及到日期、时间、时区、夏令时等。datetime
模块为我们提供了一套完整的工具来应对这一切。
核心对象类型:
datetime.date
: 只表示日期(年、月、日)。datetime.time
: 只表示时间(时、分、秒、微秒)。datetime.datetime
: 同时表示日期和时间,最常用。datetime.timedelta
: 表示两个日期或时间之间的差值。
import datetime
import time
# --- 1. 获取当前时间 ---
now = datetime.datetime.now()
print(f"当前精确时间: {now}")
today = datetime.date.today()
print(f"今天的日期: {today}")
# --- 2. 创建指定的时间对象 ---
new_year_2025 = datetime.datetime(2025, 1, 1, 0, 0, 0)
print(f"2025年新年: {new_year_2025}")
# --- 3. 时间与字符串的相互转换 ---
# a) 格式化时间为字符串 (strftime - string from time)
formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") # %Y: 四位年份, %m: 月份, %d: 日, ...
print(f"格式化后的时间字符串: {formatted_time}")
# b) 从字符串解析时间 (strptime - string parse time)
date_string = "2024-07-26 10:30:00"
parsed_time = datetime.datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")
print(f"从字符串解析的时间对象: {parsed_time}")
# --- 4. 时间运算 (使用 timedelta) ---
# 计算两天零12小时后的时间
delta = datetime.timedelta(days=2, hours=12)
future_time = now + delta
print(f"两天半之后的时间: {future_time}")
# 计算两个日期相差多少天
days_until_new_year = new_year_2025 - now
print(f"距离2025年新年还有: {days_until_new_year}")
17.2 re
模块:文本模式的瑞士军刀
正则表达式 (Regular Expression) 是一种描述文本模式的微型语言。它非常强大,但初学时可能会觉得有些晦涩。一旦掌握,你处理文本的能力将发生质的飞跃。
核心函数:
re.match(pattern, string)
: 从字符串的开头开始匹配。如果开头不匹配,就失败。re.search(pattern, string)
: 扫描整个字符串,查找第一个匹配项。re.findall(pattern, string)
: 查找所有匹配项,并以列表形式返回。re.sub(pattern, repl, string)
: 查找匹配项,并用repl
替换它们。re.split(pattern, string)
: 根据匹配项分割字符串。
常用元字符:
.
: 匹配除换行符外的任意单个字符。*
: 匹配前面的元素0次或多次。+
: 匹配前面的元素1次或多次。?
: 匹配前面的元素0次或1次。\d
: 匹配任意数字 (等价于[0-9]
)。\w
: 匹配任意字母、数字、下划线 (等价于[a-zA-Z0-9_]
)。[]
: 匹配方括号内的任意一个字符。()
: 分组,用于捕获匹配的内容。
案例:从一段文本中提取所有电子邮件地址
import re
text = "联系人: 小明 (ming@example.com), 小红 (hong@test.cn), 还有小刚 (gang@work.net)。无效邮箱: invalid-email@.com"
# 定义电子邮件的正则表达式模式
# \w+ : 匹配一个或多个字母/数字/下划线 (用户名)
# @ : 匹配 "@" 符号
# (\w+\.)+ : 匹配一个或多个 "单词." 结构 (域名,如 "example." 或 "mail.google.")
# \w+ : 匹配顶级域名 (如 "com", "cn")
email_pattern = r"[\w\.-]+@[\w\.-]+\.\w+"
# 使用 findall 查找所有匹配项
emails = re.findall(email_pattern, text)
print(f"提取到的所有邮箱: {emails}")
# 案例:替换敏感信息
# 使用 sub 将电话号码替换为 ****
log = "用户张三的电话是 13812345678, 李四的电话是 15987654321。"
# (\d{3})\d{4}(\d{4}) : 捕获前3位和后4位数字
safe_log = re.sub(r"(\d{3})\d{4}(\d{4})", r"\1****\2", log)
print(f"脱敏后的日志: {safe_log}")
17.3 json
模块:与Web世界对话
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。它是目前Web API和配置文件的事实标准。
json
模块的核心就是两个操作:编码 (dump/dumps) 和 解码 (load/loads)。
dumps
: 将Python对象 dump 成 string (字符串)。loads
: 从 string load Python对象。dump
: 将Python对象写入文件。load
: 从文件中读取JSON数据并解析为Python对象。
Python对象与JSON类型的对应关系:
Python | JSON |
---|---|
dict |
object |
list , tuple |
array |
str |
string |
int , float |
number |
True /False |
true /false |
None |
null |
import json
# --- 1. 将Python字典转换为JSON字符串 (序列化) ---
py_data = {
"name": "Alice",
"age": 30,
"is_student": False,
"courses": ["Math", "Physics"],
"address": None
}
# dumps: Python object -> JSON string
json_string = json.dumps(py_data, indent=4, ensure_ascii=False) # indent美化输出, ensure_ascii=False保证中文正常显示
print("--- JSON字符串 ---")
print(json_string)
# --- 2. 将JSON字符串解析为Python字典 (反序列化) ---
# loads: JSON string -> Python object
recreated_py_data = json.loads(json_string)
print("\n--- 解析回的Python字典 ---")
print(recreated_py_data)
print(f"姓名: {recreated_py_data['name']}")
# --- 3. 读写JSON文件 ---
# a) 将数据写入 a.json 文件
with open("a.json", "w", encoding="utf-8") as f:
json.dump(py_data, f, indent=4, ensure_ascii=False)
# b) 从 a.json 文件中读取数据
with open("a.json", "r", encoding="utf-8") as f:
data_from_file = json.load(f)
print("\n--- 从文件中读取的数据 ---")
print(data_from_file)
17.4 pickle
模块:Python对象的专属“冷冻剂”
json
只能序列化基本的数据类型。但如果你想保存一个自定义的类的实例,或者其他复杂的Python对象(如datetime
对象),json
就无能为力了。
这时,pickle
就派上用场了。pickle
可以序列化几乎任何Python对象,并将其转换为字节流。
核心优势: 能处理复杂的Python对象。
核心劣势:
- Python专用: 生成的数据只能被Python识别。
- 安全风险: 绝对不要反序列化来自不可信来源的pickle数据!因为它在反序列化时可以执行任意代码。
import pickle
class Player:
def __init__(self, name, level, inventory):
self.name = name
self.level = level
self.inventory = inventory
# 创建一个复杂的对象实例
p1 = Player("Gandalf", 99, ["staff", "pipe", "spellbook"])
# 使用 pickle.dumps 将对象序列化为字节串
pickled_data = pickle.dumps(p1)
print(f"Pickle序列化后的字节数据: {pickled_data}")
# 使用 pickle.loads 将字节串反序列化回对象
recreated_p1 = pickle.loads(pickled_data)
print(f"反序列化后的对象名字: {recreated_p1.name}")
print(f"他的物品: {recreated_p1.inventory}")
17.5 xml
模块 (简介)
XML (eXtensible Markup Language) 是一种比JSON更早、更重量级的标记语言,常见于一些企业级应用和旧的Web服务中。Python标准库提供了 xml.etree.ElementTree
模块来解析和创建XML数据。
由于JSON的流行,XML的使用场景相对减少,这里只做概念性介绍。它的结构是树形的,通过标签来组织数据,例如:
<person><name>Alice</name><age>30</age></person>
太棒了!你现在已经掌握了Python标准库中处理各种数据格式的利器。你能够:
- 用
datetime
优雅地处理时间。 - 用
re
在文本的海洋中精准捕捞。 - 用
json
与现代Web世界无缝沟通。 - 用
pickle
保存和加载Python的复杂状态。
你处理真实世界数据的能力已经非常全面。在下一章,我们将进入一个更激动人心的领域:网络与并发编程。你将学习如何让你的程序连接到互联网,获取数据,并同时执行多个任务,极大地提升程序的效率和能力。准备好,让你的Python程序“联网”并“分身”吧!