Python sqlite3.PARSE_COLNAMES 常量
上次修改时间:2025 年 4 月 15 日
本综合指南探讨 Python 的 sqlite3.PARSE_COLNAMES
常量,该常量允许在 SQLite 查询中进行高级列名解析。我们将介绍其目的、使用模式和实际示例。
基本定义
sqlite3.PARSE_COLNAMES
是一个标志,与 SQLite 连接一起使用,以启用 SQL 查询中列名的解析。 设置后,它允许在列名中使用特殊语法进行类型转换。
主要特征:它与 sqlite3.connect
一起使用,通过列名注释启用类型转换,并提供对查询结果的更多控制。 它与 detect_types
参数一起使用。
基本的 PARSE_COLNAMES 用法
这是一个简单的例子,展示了如何使用 PARSE_COLNAMES
启用列名解析以进行基本的类型转换。
import sqlite3 with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE test (id INTEGER, data TEXT)''') cursor.execute("INSERT INTO test VALUES (1, 'Sample data')") # Query with column name annotation for type conversion cursor.execute('''SELECT data AS "data [str]" FROM test''') row = cursor.fetchone() print(type(row[0])) # <class 'str'>
此示例创建一个启用了 PARSE_COLNAMES
的内存数据库。 查询使用 AS "column [type]"
语法来指定结果列的类型转换。
括号中的类型(如 [str]
)告诉 SQLite 如何转换列值。 这对于自定义类型或您需要特定的 Python 类型时特别有用。
日期类型转换
此示例演示了使用 PARSE_COLNAMES
自动将日期字符串转换为 Python datetime.date
对象。
import sqlite3 import datetime def adapt_date(date): return date.isoformat() def convert_date(value): return datetime.date.fromisoformat(value.decode()) # Register type adapters sqlite3.register_adapter(datetime.date, adapt_date) sqlite3.register_converter("date", convert_date) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE events (id INTEGER, event_date TEXT)''') today = datetime.date.today() cursor.execute("INSERT INTO events VALUES (1, ?)", (today,)) # Query with date type conversion cursor.execute('''SELECT event_date AS "event_date [date]" FROM events''') row = cursor.fetchone() print(type(row[0]), row[0]) # <class 'datetime.date'> YYYY-MM-DD
我们首先注册 datetime.date
的适配器和转换器函数。 然后,查询在列别名中使用 [date]
来触发转换。
此模式对于在数据库中使用日期,同时在应用程序逻辑中维护正确的 Python 日期对象非常有用。
自定义类型转换
此示例展示了如何在更高级的场景中使用带有自定义 Python 类型的 PARSE_COLNAMES
。
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 adapt_point(point): return f"{point.x};{point.y}".encode() def convert_point(value): x, y = value.decode().split(';') return Point(float(x), float(y)) # Register custom type sqlite3.register_adapter(Point, adapt_point) sqlite3.register_converter("point", convert_point) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE shapes (id INTEGER, coordinates TEXT)''') p = Point(3.5, 4.2) cursor.execute("INSERT INTO shapes VALUES (1, ?)", (p,)) # Query with custom type conversion cursor.execute('''SELECT coordinates AS "coordinates [point]" FROM shapes''') row = cursor.fetchone() print(type(row[0]), row[0]) # <class '__main__.Point'> Point(3.5, 4.2)
我们定义了一个自定义 Point
类并注册适配器/转换器函数。 然后,查询使用 [point]
将存储的字符串转换回 Point 对象。
这种技术非常强大,可以将复杂的 Python 对象存储在 SQLite 中,同时在检索时保持其原始类型。
多列转换
此示例演示了使用 PARSE_COLNAMES
以及不同的类型在单个查询中转换多个列。
import sqlite3 import datetime # Register date converters sqlite3.register_adapter(datetime.date, lambda d: d.isoformat()) sqlite3.register_converter("date", lambda b: datetime.date.fromisoformat(b.decode())) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE records (id INTEGER, record_date TEXT, value REAL)''') cursor.execute("INSERT INTO records VALUES (1, ?, 42.5)", (datetime.date.today(),)) # Convert multiple columns with different types cursor.execute('''SELECT id AS "id [int]", record_date AS "record_date [date]", value AS "value [float]" FROM records''') row = cursor.fetchone() print(type(row[0]), type(row[1]), type(row[2])) # <class 'int'> <class 'datetime.date'> <class 'float'>
查询将三个列转换为不同的 Python 类型:整数、日期和浮点数。 每个列都使用带有相应类型的 AS "column [type]"
语法。
这种方法提供了对每个返回列的类型的细粒度控制,这可以简化处理查询结果的应用程序代码。
与 PARSE_DECLTYPES 结合
此示例展示了 PARSE_COLNAMES
如何与 PARSE_DECLTYPES
协同工作以进行全面的类型处理。
import sqlite3 import datetime # Register type handlers sqlite3.register_adapter(datetime.date, lambda d: d.isoformat()) sqlite3.register_converter("date", lambda b: datetime.date.fromisoformat(b.decode())) # Use both PARSE_DECLTYPES and PARSE_COLNAMES with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() # Declare column type in table definition cursor.execute('''CREATE TABLE events (id INTEGER, event_date DATE)''') today = datetime.date.today() cursor.execute("INSERT INTO events VALUES (1, ?)", (today,)) # Override declared type with column name annotation cursor.execute('''SELECT event_date AS "event_date [str]" FROM events''') row = cursor.fetchone() print(type(row[0])) # <class 'str'> (overridden by column name)
我们使用按位 OR (|
) 组合这两个标志。 该表将 event_date
声明为 DATE 类型,但查询使用列别名中的 [str]
覆盖了它。
这种组合提供了最大的灵活性:声明的类型用于正常操作,并且能够在需要时通过列名覆盖。
处理 NULL 值
此示例演示了 PARSE_COLNAMES
在类型转换期间如何处理 NULL 值。
import sqlite3 import datetime # Register date converter sqlite3.register_converter("date", lambda b: datetime.date.fromisoformat(b.decode())) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE tasks (id INTEGER, due_date TEXT)''') # Insert both date and NULL values cursor.execute("INSERT INTO tasks VALUES (1, ?)", (datetime.date.today().isoformat(),)) cursor.execute("INSERT INTO tasks VALUES (2, NULL)") # Query with type conversion cursor.execute('''SELECT due_date AS "due_date [date]" FROM tasks''') rows = cursor.fetchall() for row in rows: print(type(row[0]), row[0]) # <class 'datetime.date'> YYYY-MM-DD # <class 'NoneType'> None
该示例表明,即使指定了类型转换,数据库中的 NULL 值在 Python 中仍然保留为 None
。 不会为 NULL 值调用转换器函数。
在编写处理数据库中可能为 NULL 的可选字段的查询结果的代码时,记住此行为非常重要。
复杂类型转换
这个高级示例演示了将带有 JSON 数据的 PARSE_COLNAMES
用于复杂类型转换场景。
import sqlite3 import json def adapt_json(data): return json.dumps(data).encode() def convert_json(value): return json.loads(value.decode()) # Register JSON converter sqlite3.register_adapter(dict, adapt_json) sqlite3.register_converter("json", convert_json) with sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_COLNAMES) as conn: cursor = conn.cursor() cursor.execute('''CREATE TABLE configs (id INTEGER, settings TEXT)''') config = {'theme': 'dark', 'notifications': True} cursor.execute("INSERT INTO configs VALUES (1, ?)", (config,)) # Query with JSON conversion cursor.execute('''SELECT settings AS "settings [json]" FROM configs''') row = cursor.fetchone() print(type(row[0]), row[0]['theme']) # <class 'dict'> dark
我们为 Python 字典到 JSON 字符串以及反向注册转换器。 查询使用 [json]
自动将存储的 JSON 字符串转换回 Python 字典。
这种模式对于在 SQLite 中存储结构化配置数据或其他复杂对象,同时保持对原始 Python 数据结构的轻松访问非常有用。
最佳实践
- 使用描述性类型名称:在方括号中选择清晰的类型名称
- 仔细注册转换器:确保转换器处理所有边缘情况
- 与 PARSE_DECLTYPES 结合:用于全面的类型处理
- 记录类型转换:明确列类型期望
- 处理 NULL 值:确保您的代码处理潜在的 NULL 值
资料来源
作者
列出所有 Python 教程。