如何为Python运行时动态创建的类添加类型提示?
问题:如何为动态生成数据类的SQLite包装类添加类型提示?
我编写了一个用于管理SQLite数据库连接的简单包装类,借助row_factory和recordclass让查询结果的每一行都以运行时动态生成的数据类实例形式返回。代码如下:
import sqlite3 import recordclass class DBConnection: def __init__(self, file_path): self.connection = sqlite3.connect(file_path) self.connection.row_factory = self.make_row_factory( recordclass.make_dataclass, fast_new=True, ) self.cursor = self.connection.cursor() def make_row_factory(self, cls_factory, **kw): def row_factory(cursor, row, cls=[None]): rf = cls[0] if rf is None: fields = [col[0] for col in cursor.description] cls[0] = cls_factory("Row", fields, **kw) return cls[0](*row) return rf(*row) return row_factory def query(self, query: str): result = self.cursor.execute(query) return result.fetchall()
目前遇到的核心问题:
- 无法直接为
query方法添加返回类型提示(即def query(self, query: str) -> list[????]),因为生成的数据类仅在运行时存在 make_row_factory和内部的row_factory方法的类型提示也存在同样的挑战
解决方案
1. 用泛型+TypeVar实现动态类型支持
这是最严谨的方案,能让类型检查器识别动态行类型的结构:
首先导入所需类型模块,定义泛型类型变量并让DBConnection继承Generic:
import sqlite3 import recordclass from typing import TypeVar, Generic, List, Callable, Any, Tuple, Optional RowT = TypeVar("RowT") class DBConnection(Generic[RowT]):
然后修改query方法的类型提示:
def query(self, query: str) -> List[RowT]: result = self.cursor.execute(query) return result.fetchall()
使用者可以在实例化时手动指定预期的行类型(比如提前定义对应表结构的dataclass),类型检查器也能通过上下文自动推断类型。
2. 为工厂方法添加类型提示
针对make_row_factory和内部的row_factory,可以用Callable描述函数签名,结合泛型变量标记动态类型:
def make_row_factory( self, cls_factory: Callable[[str, List[str], Any], type[RowT]], **kw: Any ) -> Callable[[sqlite3.Cursor, Tuple[Any, ...]], RowT]: def row_factory( cursor: sqlite3.Cursor, row: Tuple[Any, ...], cls: List[Optional[type[RowT]]] = [None] ) -> RowT: rf = cls[0] if rf is None: fields = [col[0] for col in cursor.description] cls[0] = cls_factory("Row", fields, **kw) return cls[0](*row) return rf(*row) return row_factory
说明:
cls_factory的类型描述:接收类名、字段列表、关键字参数,返回一个RowT类型的类- 返回的
row_factory类型描述:接收游标和行数据元组,返回RowT实例
3. 简化方案:直接使用Any
如果不需要严格的类型检查,用Any可以快速完成类型提示,适合快速开发场景:
from typing import List, Any def query(self, query: str) -> List[Any]: result = self.cursor.execute(query) return result.fetchall()
这种方式最简洁,但会丢失类型检查的优势,仅建议在小型项目或原型开发中使用。
内容的提问来源于stack exchange,提问作者Apreche
相关产品推荐
相关产品推荐

