Python sqlite3.register_converter 函数
上次修改时间:2025 年 4 月 15 日
本综合指南探讨了 Python 的 sqlite3.register_converter
函数,该函数允许在从 SQLite 检索数据时进行自定义类型转换。
基本定义
sqlite3.register_converter
函数注册一个可调用对象,用于将特定类型的 SQLite 值转换为 Python 对象。它与 sqlite3.connect
中的 detect_types
参数一起使用。
主要特征:它将 SQLite 类型映射到 Python 对象,支持复杂的类型处理,并与内置类型和自定义类型一起使用。转换发生在从数据库获取数据时。
基本类型转换
此示例显示如何为 SQLite DATE 类型注册一个转换器,将其转换为 Python date 对象。
import sqlite3 from datetime import date def convert_date(val): return date.fromisoformat(val.decode()) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("DATE", convert_date) conn.execute("CREATE TABLE events(id INTEGER, event_date DATE)") conn.execute("INSERT INTO events VALUES (1, '2025-04-15')") row = conn.execute("SELECT * FROM events").fetchone() print(row[1], type(row[1])) # 2025-04-15 <class 'datetime.date'>
转换器函数接受来自 SQLite 的字节对象并返回一个 Python date。 PARSE_DECLTYPES
标志启用从列声明中进行类型检测。
此模式对于在提取操作期间自动将数据库原生格式转换为 Python 对象非常有用。
转换 JSON 数据
此示例演示了如何自动将存储在 SQLite 中的 JSON 字符串转换为 Python 字典。
import sqlite3 import json def convert_json(val): return json.loads(val.decode()) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("JSON", convert_json) conn.execute("CREATE TABLE configs(id INTEGER, settings JSON)") conn.execute("INSERT INTO configs VALUES (1, '{\"theme\": \"dark\", \"notifications\": true}')") row = conn.execute("SELECT * FROM configs").fetchone() print(row[1]['theme']) # dark
转换器在检索数据时自动反序列化 JSON 字符串。 这对于在 SQLite 中存储半结构化数据特别有用。
请注意,SQLite 没有原生的 JSON 类型 - 我们使用类型名称作为转换器识别的约定。
自定义对象转换
此示例显示如何将 SQLite 值转换为自定义 Python 对象。
import sqlite3 class Point: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return f"Point({self.x}, {self.y})" def convert_point(val): x, y = map(float, val.decode().split(',')) return Point(x, y) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("POINT", convert_point) conn.execute("CREATE TABLE shapes(id INTEGER, location POINT)") conn.execute("INSERT INTO shapes VALUES (1, '3.5,4.2')") row = conn.execute("SELECT * FROM shapes").fetchone() print(row[1]) # Point(3.5, 4.2)
在这里,我们将点作为逗号分隔的字符串存储在 SQLite 中,并在检索时将其转换为 Point 对象。 转换器处理解析逻辑。
此模式对于需要在关系数据库中持久化的特定于域的对象很有用。
二进制数据转换
此示例演示了将二进制数据转换为自定义 Python 对象。
import sqlite3 import pickle class CustomData: def __init__(self, data): self.data = data def __repr__(self): return f"CustomData({self.data!r})" def convert_custom(val): return pickle.loads(val) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("CUSTOM", convert_custom) original = CustomData([1, 2, 3]) conn.execute("CREATE TABLE data_store(id INTEGER, data CUSTOM)") conn.execute("INSERT INTO data_store VALUES (1, ?)", (pickle.dumps(original),)) row = conn.execute("SELECT * FROM data_store").fetchone() print(row[1]) # CustomData([1, 2, 3])
此示例使用 pickle 将 Python 对象序列化为二进制格式,以便存储在 SQLite 中。 转换器在检索时取消 pickle 数据。
虽然功能强大,但在加载不受信任的数据时,请谨慎使用 pickle,因为它存在安全隐患。
多个转换器
此示例显示了为不同的 SQLite 类型注册多个转换器。
import sqlite3 from datetime import datetime, date def convert_datetime(val): return datetime.strptime(val.decode(), "%Y-%m-%d %H:%M:%S") def convert_date(val): return date.fromisoformat(val.decode()) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("DATETIME", convert_datetime) sqlite3.register_converter("DATE", convert_date) conn.execute("""CREATE TABLE events( id INTEGER, event_date DATE, created_at DATETIME)""") conn.execute("""INSERT INTO events VALUES (1, '2025-04-15', '2025-04-15 14:30:00')""") row = conn.execute("SELECT * FROM events").fetchone() print(f"Date: {row[1]}, Datetime: {row[2]}")
在这里,我们为 DATE 和 DATETIME 类型注册单独的转换器。 每个转换器都处理其特定格式并返回适当的 Python 对象。
这种方法可以对如何将不同的 SQLite 类型转换为 Python 对象进行细粒度的控制。
转换器中的错误处理
此示例演示了转换器函数中的正确错误处理。
import sqlite3 from datetime import date def safe_date_converter(val): try: return date.fromisoformat(val.decode()) except (ValueError, AttributeError) as e: print(f"Conversion error: {e}") return None with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: sqlite3.register_converter("DATE", safe_date_converter) conn.execute("CREATE TABLE events(id INTEGER, event_date DATE)") conn.execute("INSERT INTO events VALUES (1, 'invalid-date')") row = conn.execute("SELECT * FROM events").fetchone() print(row[1]) # None (due to conversion error)
转换器包括错误处理以管理格式错误的数据。 当转换失败时,它返回 None,从而防止应用程序崩溃。
强大的转换器应始终处理输入数据中的潜在错误,以保持应用程序的稳定性。
与适配器结合
此示例显示了将转换器与适配器一起使用以进行双向转换。
import sqlite3 from decimal import Decimal def adapt_decimal(d): return str(d) def convert_decimal(val): return Decimal(val.decode()) # Register the adapter and converter sqlite3.register_adapter(Decimal, adapt_decimal) sqlite3.register_converter("DECIMAL", convert_decimal) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) as conn: conn.execute("CREATE TABLE prices(id INTEGER, amount DECIMAL)") price = Decimal('19.99') conn.execute("INSERT INTO prices VALUES (1, ?)", (price,)) row = conn.execute("SELECT * FROM prices").fetchone() print(row[1], type(row[1])) # 19.99 <class 'decimal.Decimal'>
适配器在存储数据时将 Python 对象转换为与 SQLite 兼容的格式,而转换器在检索时将其转换回来。 这提供了无缝的双向转换。
该组合功能强大,可以处理自定义类型,同时保持数据库兼容性。
最佳实践
- 处理错误: 转换器应优雅地管理格式错误的数据
- 使用高效格式: 选择紧凑的存储表示形式
- 文档类型: 清楚地记录自定义类型约定
- 考虑性能: 复杂的转换可能会影响速度
- 彻底测试: 验证类型转换中的边缘情况
资料来源
作者
列出所有 Python 教程。