本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南,旨在帮助读者从基础入门到项目实战,全面提升编程能力。文章结构由 5 个版块组成,内容层层递进,逻辑清晰。
无论你是 Python3 初学者,还是希望提升实战能力的开发者,本系列文章都能为你提供清晰的学习路径和实用的编程技巧,助你快速成长为 Python3 编程高手。
Python 数据持久化是指将程序运行中的数据以某种形式存储到持久化介质(如硬盘、数据库等)中,使其在程序终止后依然存在,以便后续重新加载和使用。简单来说,持久化是为了让数据在程序结束后依然可访问。
普通文本/二进制文件:通过 open()
函数读写文件。
# 写入数据
with open("data.txt", "w") as f:
f.write("Hello, World!")
# 读取数据
with open("data.txt", "r") as f:
data = f.read()
JSON 文件:使用 json
模块处理结构化数据(适合字典、列表等)。
import json
data = {"name": "Alice", "age": 30}
# 写入 JSON 文件
with open("data.json", "w") as f:
json.dump(data, f)
# 读取 JSON 文件
with open("data.json", "r") as f:
loaded_data = json.load(f)
CSV 文件:使用 csv
模块处理表格数据。
import csv
# 写入 CSV 文件
with open("data.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["Name", "Age"])
writer.writerow(["Alice", 30])
pickle
pickle
是 Python 专用的,存在安全风险(不可反序列化不受信任的数据)。import pickle
data = {"key": "value"}
# 序列化到文件
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
# 反序列化
with open("data.pkl", "rb") as f:
loaded_data = pickle.load(f)
sqlite3
import sqlite3
# 连接数据库(不存在则创建)
conn = sqlite3.connect("mydatabase.db")
cursor = conn.cursor()
# 创建表
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
# 插入数据
cursor.execute("INSERT INTO users (name) VALUES (?)", ("Alice",))
conn.commit()
# 查询数据
cursor.execute("SELECT * FROM users")
print(cursor.fetchall()) # 输出:[(1, 'Alice')]
shelve
pickle
序列化数据。import shelve
# 写入数据
with shelve.open("mydata") as db:
db["user"] = {"name": "Alice", "age": 30}
# 读取数据
with shelve.open("mydata") as db:
print(db["user"]) # 输出:{'name': 'Alice', 'age': 30}
SQLAlchemy
或 Django ORM
等库,将数据库表映射为 Python 类,简化数据库操作。pymongo
(MongoDB)、redis
等库连接非关系型数据库,适合灵活的数据结构。方法 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
文本/JSON/CSV | 简单配置、小型数据 | 易读易写,跨语言兼容 | 不适合复杂或大规模数据 |
pickle |
存储 Python 对象 | 支持复杂对象 | 不安全,仅限 Python 使用 |
sqlite3 |
结构化数据,需要查询 | 轻量级,无需额外服务 | 不适合高并发或大规模数据 |
shelve |
快速键值存储 | 简单易用 | 依赖 pickle ,有安全风险 |
ORM/NoSQL | 大型项目、复杂需求 | 功能强大,扩展性好 | 学习成本高,需要额外部署 |
数据持久化的核心目的是长期保存数据。Python 提供了多种工具,选择时需根据数据规模、结构、安全性需求以及是否需要跨程序共享来决定。对于简单场景,JSON 或文本文件足矣;复杂场景可能需要数据库或 ORM 框架。
以下展示的是 10个Python数据持久化的经典应用场景及完整代码示例,涵盖多种存储方式和实际需求:
import json
# 写入配置
config = {"theme": "dark", "language": "zh", "font_size": 12}
with open("config.json", "w") as f:
json.dump(config, f)
# 读取配置
with open("config.json", "r") as f:
loaded_config = json.load(f)
print(loaded_config) # 输出: {'theme': 'dark', 'language': 'zh', 'font_size': 12}
import datetime
# 追加日志
log_message = f"{datetime.datetime.now()} - 用户登录成功\n"
with open("app.log", "a") as f:
f.write(log_message)
# 查看日志
with open("app.log", "r") as f:
print(f.read()) # 输出: 2023-10-01 12:00:00.000000 - 用户登录成功
import csv
# 写入CSV数据
data = [["姓名", "年龄"], ["Alice", 30], ["Bob", 25]]
with open("users.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(data)
# 读取CSV数据
with open("users.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print(row) # 输出: ['姓名', '年龄'] → ['Alice', '30'] → ['Bob', '25']
import pickle
import time
# 模拟耗时计算函数
def heavy_calculation():
time.sleep(2)
return {"result": 42}
# 检查缓存是否存在
try:
with open("cache.pkl", "rb") as f:
data = pickle.load(f)
except FileNotFoundError:
data = heavy_calculation()
with open("cache.pkl", "wb") as f:
pickle.dump(data, f)
print(data) # 输出: {'result': 42}(首次运行会计算,之后直接读取)
import sqlite3
# 连接数据库
conn = sqlite3.connect("users.db")
cursor = conn.cursor()
# 创建表
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
# 插入数据
cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", ("Alice", "[email protected]"))
conn.commit()
# 查询数据
cursor.execute("SELECT * FROM users")
print(cursor.fetchall()) # 输出: [(1, 'Alice', '[email protected]')]
conn.close() # 关闭连接
import shelve
# 写入数据
with shelve.open("user_db") as db:
db["alice"] = {"age": 30, "role": "admin"}
db["bob"] = {"age": 25, "role": "user"}
# 读取数据
with shelve.open("user_db") as db:
print(db["alice"]) # 输出: {'age': 30, 'role': 'admin'}
import h5py
import numpy as np
# 创建HDF5文件并保存数据
data = np.random.rand(100, 100)
with h5py.File("scientific_data.h5", "w") as f:
f.create_dataset("dataset", data=data)
# 读取数据
with h5py.File("scientific_data.h5", "r") as f:
loaded_data = f["dataset"][:]
print(loaded_data.shape) # 输出: (100, 100)
import redis
# 连接Redis
r = redis.Redis(host='localhost', port=6379, db=0)
# 存储会话数据
r.set("user:1001", '{"name": "Alice", "last_login": "2023-10-01"}')
# 读取会话数据
data = r.get("user:1001")
print(data.decode()) # 输出: {"name": "Alice", "last_login": "2023-10-01"}
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
# 定义数据模型
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
# 连接数据库
engine = create_engine('sqlite:///orm_users.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# 插入数据
new_user = User(name="Alice", email="[email protected]")
session.add(new_user)
session.commit()
# 查询数据
users = session.query(User).all()
for user in users:
print(user.name, user.email) # 输出: Alice [email protected]
# 写入二进制数据(如图片)
binary_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR...' # 模拟PNG文件头
with open("image.png", "wb") as f:
f.write(binary_data)
# 读取二进制数据
with open("image.png", "rb") as f:
loaded_data = f.read()
print(loaded_data[:8]) # 输出: b'\x89PNG\r\n\x1a\n\x00'
以下是 10个Python数据持久化中的典型错误及其解决方案,通过代码示例分析原因并提供修正方法:
# ❌ 错误代码
f = open("data.txt", "w")
f.write("重要数据")
# 忘记关闭文件,数据可能未写入磁盘!
# ✅ 修正代码
with open("data.txt", "w") as f: # 使用 with 自动关闭文件
f.write("重要数据")
import json
from datetime import datetime
# ❌ 错误代码
data = {"time": datetime.now()}
json.dump(data, open("data.json", "w")) # 报错: TypeError (datetime不可序列化)
# ✅ 修正代码
data = {"time": str(datetime.now())} # 转换为字符串
json.dump(data, open("data.json", "w")) # 正常写入
import sqlite3
# ❌ 错误代码(直接拼接SQL)
user_input = "Alice'; DROP TABLE users;--"
cursor.execute(f"SELECT * FROM users WHERE name = '{user_input}'") # 危险!
# ✅ 修正代码(参数化查询)
cursor.execute("SELECT * FROM users WHERE name = ?", (user_input,)) # 安全
import pickle
# ❌ 错误代码(反序列化不可信数据)
with open("malicious.pkl", "rb") as f:
data = pickle.load(f) # 可能执行恶意代码!
# ✅ 修正方案:避免反序列化不可信数据,改用JSON等安全格式。
import sqlite3
# ❌ 错误代码(未处理并发)
conn1 = sqlite3.connect("test.db")
conn2 = sqlite3.connect("test.db") # 多连接同时写入会报错: sqlite3.OperationalError
# ✅ 修正代码(使用单一连接或处理异常)
conn = sqlite3.connect("test.db", timeout=10) # 设置超时等待
import shelve
# ❌ 错误代码
db = shelve.open("data")
db["key"] = [1, 2, 3]
db["key"].append(4) # 直接修改未同步,数据不会保存!
db.close()
# ✅ 修正代码
db = shelve.open("data", writeback=True) # 启用写回模式
db["key"] = [1, 2, 3]
db["key"].append(4) # 修改后自动同步
db.close()
# ❌ 错误代码(路径不存在)
with open("non_existent_folder/data.txt", "w") as f: # FileNotFoundError
f.write("数据")
# ✅ 修正代码
import os
os.makedirs("non_existent_folder", exist_ok=True) # 创建目录
with open("non_existent_folder/data.txt", "w") as f:
f.write("数据")
import csv
# ❌ 错误代码(Windows换行符问题)
with open("data.csv", "w") as f:
writer = csv.writer(f)
writer.writerow(["A", "B"]) # 可能多出空行
# ✅ 修正代码
with open("data.csv", "w", newline="") as f: # 指定newline参数
writer = csv.writer(f)
writer.writerow(["A", "B"])
# ❌ 错误代码(写入和读取编码不一致)
with open("data.txt", "w", encoding="gbk") as f:
f.write("中文数据")
with open("data.txt", "r", encoding="utf-8") as f: # UnicodeDecodeError
print(f.read())
# ✅ 修正代码
with open("data.txt", "w", encoding="utf-8") as f:
f.write("中文数据")
with open("data.txt", "r", encoding="utf-8") as f: # 正常读取
print(f.read())
import sqlite3
# ❌ 错误代码
conn = sqlite3.connect("test.db")
cursor = conn.cursor()
cursor.execute("INSERT INTO users (name) VALUES ('Alice')") # 未提交,数据未保存!
conn.close()
# ✅ 修正代码
conn = sqlite3.connect("test.db")
cursor = conn.cursor()
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
conn.commit() # 显式提交事务
conn.close()
以下哪种文件格式适合存储结构化数据且跨语言兼容?
A. .pkl
B. .json
C. .bin
D. .xlsx
答案:B
使用 with open("data.txt", "w") as f:
的优点是?
A. 自动处理文件编码
B. 自动关闭文件
C. 支持二进制写入
D. 允许并发写入
答案:B
防止 SQL 注入攻击的最佳方法是?
A. 使用字符串拼接
B. 参数化查询
C. 过滤特殊字符
D. 禁用数据库事务
答案:B
pickle
模块的主要缺点是?
A. 仅支持文本数据
B. 不可跨语言使用且不安全
C. 存储效率低
D. 不支持复杂对象
答案:B
以下哪种方法可以将 Python 字典写入 CSV 文件?
A. csv.writerows()
B. json.dump()
C. pickle.dump()
D. sqlite3.execute()
答案:A
在 SQLite 中提交事务的命令是?
A. conn.save()
B. conn.commit()
C. cursor.flush()
D. conn.close()
答案:B
使用 shelve
模块时,直接修改已存储的列表数据会导致?
A. 数据自动更新
B. 数据未保存
C. 文件损坏
D. 程序崩溃
答案:B
以下哪个库适合存储科学计算中的大型数组?
A. csv
B. h5py
C. sqlite3
D. shelve
答案:B
以下代码可能引发什么错误?
data = {"time": datetime.now()}
json.dump(data, open("data.json", "w"))
A. FileNotFoundError
B. TypeError
C. KeyError
D. UnicodeEncodeError
答案:B
Redis 属于哪种类型的数据库?
A. 关系型数据库
B. 文档数据库
C. 键值存储数据库
D. 图数据库
答案:C
以下哪种方法可以安全存储用户密码?
A. 明文保存到文本文件
B. 使用 pickle
序列化
C. 使用加密算法(如 bcrypt)
D. 直接写入 CSV 文件
答案:C
在 Windows 系统写入 CSV 文件时出现多余空行,应该如何解决?
A. 指定 encoding="utf-8"
B. 设置 newline=""
C. 使用 with
语句
D. 以二进制模式写入
答案:B
以下代码的输出是?
import sqlite3
conn = sqlite3.connect(":memory:")
cursor = conn.cursor()
cursor.execute("SELECT 1 + 1")
print(cursor.fetchone()[0])
A. 2
B. None
C. 报错
D. (2,)
答案:A
使用 pymongo
插入文档到 MongoDB 的方法是?
A. insert()
B. add_document()
C. insert_one()
D. save()
答案:C
以下哪种操作可以防止大文件读取时内存溢出?
A. 使用 f.read()
B. 逐行读取
C. 使用 pickle
D. 启用压缩
答案:B
将字典写入 JSON 文件的函数是 json.______
。
答案:dump
在 SQLite 中创建游标对象的命令是 conn.______()
。
答案:cursor
使用 csv
模块写入 CSV 文件时,设置 newline=""
可以避免______问题。
答案:换行符混乱
使用 shelve
模块时,设置 writeback=True
的作用是______。
答案:自动同步修改数据
在 Redis 中设置键值对的命令是 r.______("key", "value")
。
答案:set
使用 pickle
模块反序列化数据的函数是 pickle.______
。
答案:load
在 sqlite3
中执行查询语句后,获取所有结果的函数是 cursor.______()
。
答案:fetchall
使用 h5py
创建 HDF5 数据集的函数是 f.create______("name", data)
。
答案:dataset
在 Python 中处理文件路径时,应使用 os.path
模块的 ______
函数拼接路径。
答案:join
使用 cryptography
加密数据时,生成密钥的函数是 Fernet.______()
。
答案:generate_key
将字典数据保存为 JSON 文件
要求:将 {"name": "Alice", "age": 25}
写入 user.json
。
import json
data = {"name": "Alice", "age": 25}
with open("user.json", "w") as f:
json.dump(data, f)
使用 SQLite 创建表并插入数据
要求:创建表 students
(字段:id、name、score),插入一条数据。
import sqlite3
conn = sqlite3.connect("school.db")
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY, name TEXT, score REAL)")
cursor.execute("INSERT INTO students (name, score) VALUES (?, ?)", ("Bob", 90.5))
conn.commit()
conn.close()
读取 CSV 文件并打印内容
要求:读取 data.csv
文件,逐行打印。
import csv
with open("data.csv", "r") as f:
reader = csv.reader(f)
for row in reader:
print(row)
使用 Pickle 序列化和反序列化对象
要求:将一个列表 [1, 2, 3]
序列化为 data.pkl
,再读取回来。
import pickle
data = [1, 2, 3]
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
with open("data.pkl", "rb") as f:
loaded_data = pickle.load(f)
使用 Redis 存储和读取数据
要求:连接本地 Redis,设置键 "counter"
值为 100
,读取并打印。
import redis
r = redis.Redis(host="localhost", port=6379, db=0)
r.set("counter", 100)
value = r.get("counter")
print(value.decode()) # 输出: 100
以下是 3个实用且新颖的Python迷你项目,涵盖不同应用场景,包含完整代码、注释和测试案例:
功能:命令行任务管理,支持增删改查,数据存储到SQLite。
import sqlite3
import argparse
def init_db():
"""初始化数据库"""
conn = sqlite3.connect("todos.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY,
task TEXT,
done BOOLEAN DEFAULT 0
)
""")
conn.commit()
conn.close()
def add_task(task):
"""添加任务"""
conn = sqlite3.connect("todos.db")
cursor = conn.cursor()
cursor.execute("INSERT INTO todos (task) VALUES (?)", (task,))
conn.commit()
conn.close()
def list_tasks():
"""列出所有任务"""
conn = sqlite3.connect("todos.db")
cursor = conn.cursor()
cursor.execute("SELECT id, task, done FROM todos")
tasks = cursor.fetchall()
for task in tasks:
status = "✓" if task[2] else "✗"
print(f"{task[0]}. [{status}] {task[1]}")
conn.close()
if __name__ == "__main__":
init_db()
parser = argparse.ArgumentParser(description="待办事项管理器")
parser.add_argument("--add", help="添加新任务")
args = parser.parse_args()
if args.add:
add_task(args.add)
print("任务添加成功!")
list_tasks()
运行命令:
python todo.py --add "学习Python"
# 输出:
# 任务添加成功!
# 1. [✗] 学习Python
功能:批量转换Markdown文件为HTML,保留基础格式。
import markdown
import glob
def md_to_html(input_path, output_dir):
"""转换单个Markdown文件为HTML"""
with open(input_path, "r", encoding="utf-8") as f:
md_content = f.read()
html_content = markdown.markdown(md_content)
output_path = os.path.join(output_dir, os.path.basename(input_path).replace(".md", ".html"))
with open(output_path, "w", encoding="utf-8") as f:
f.write(f"\n\n\n{html_content}\n\n")
return output_path
# 批量转换
for md_file in glob.glob("docs/*.md"):
result = md_to_html(md_file, "html_output")
print(f"生成: {result}")
# 输出:
# 生成: html_output/example1.html
# 生成: html_output/example2.html
功能:评估密码复杂度,给出安全等级。
import re
def check_password_strength(password):
"""检测密码强度"""
strength = 0
if len(password) >= 8:
strength += 1
if re.search(r"[A-Z]", password):
strength += 1
if re.search(r"[a-z]", password):
strength += 1
if re.search(r"[0-9]", password):
strength += 1
if re.search(r"[!@#$%^&*()]", password):
strength += 1
return {
0: "极弱",
1: "弱",
2: "中",
3: "强",
4: "极强",
5: "无敌"
}.get(strength, "未知")
# 测试案例
print(check_password_strength("password")) # 输出: 弱
print(check_password_strength("Pass123!")) # 输出: 极强
运行环境:需安装以下库:
pip install requests markdown