SelfDB:用 Python 元编程把数据库变成你的“私有记忆库”

> SelfDB 是一个将 SQLite 数据库封装为 Python 对象属性的库,让你像操作普通对象一样持久化数据,无需编写 SQL 或 ORM 映射。 ## 一、它到底解决了什么痛点? 在 Python 开发中,持久化数据通常有几种选择: 1. **直接写 SQL** — 需要手动管理连接、游标、事务,代码冗长且容易出错。 2. **使用 ORM(如 SQLAlchemy、Django ORM)** — 需要定义模型类、字段映射、迁移脚本,对于小项目或原型开发显得过重。 3. **使用轻量级键值存储(如 shelve、pickle)** — 虽然简单,但缺乏类型安全、查询能力和并发控制。 SelfDB 的核心理念是:**如果你只需要将 Python 对象持久化到本地文件,为什么不能像访问普通属性一样直接读写?** 它通过 Python 的元编程(`__getattr__`、`__setattr__`)将对象的每个属性自动映射到 SQLite 表的一个列,每次赋值自动触发数据库写入,每次读取自动从数据库加载。 这意味着: - 你不需要写任何 SQL 语句。 - 你不需要定义模型类或字段声明。 - 你不需要关心数据库连接的生命周期。 - 你不需要手动调用 `save()` 或 `commit()`。 ## 二、快速上手:安装与第一个例子 ### 安装 bash pip install selfdb ### 基本用法 python from selfdb import SelfDB # 创建一个数据库连接(文件会自动创建) db = SelfDB('mydata.db') # 直接赋值,自动持久化 db.user_name = 'Alice' db.user_age = 30 db.user_tags = ['admin', 'developer'] # 列表自动序列化 # 直接读取,自动从数据库加载 print(db.user_name) # 输出: Alice print(db.user_age) # 输出: 30 print(db.user_tags) # 输出: ['admin', 'developer'] # 删除属性 del db.user_age 就这么简单。每次赋值,SelfDB 内部会执行 SQLite 的 `INSERT OR REPLACE`,每次读取会执行 `SELECT`。你甚至不需要手动关闭连接,SelfDB 在对象销毁或程序退出时会自动清理。 ### 复杂数据类型的处理 SelfDB 支持 Python 的基本类型(int、float、str、bool),对于列表、字典、元组等复合类型,它会自动使用 JSON 序列化存储。这意味着你可以直接存储嵌套结构: python db.user_profile = { 'name': 'Bob', 'skills': ['Python', 'C++'], 'metadata': {'level': 2, 'active': True} } # 读取时自动反序列化为字典 profile = db.user_profile print(profile['skills'][0]) # 输出: Python ### 事务与批量操作 虽然每个赋值都是独立写入,但 SelfDB 也提供了上下文管理器来支持原子性: python with db.transaction(): db.key1 = 'value1' db.key2 = 'value2' # 如果中途异常,所有操作回滚 ## 三、核心亮点深入分析 ### 1. 零配置、零样板代码 这是 SelfDB 最大的吸引力。相比 SQLAlchemy 需要定义 `Base`、`Column`、`session` 等概念,SelfDB 只需要一行 `SelfDB('file.db')` 就完成了所有初始化。特别适合: - 快速原型验证 - 脚本工具的状态持久化 - 配置管理(替代 JSON/YAML 文件) - 教学演示(让学生专注于逻辑而非数据库细节) ### 2. 基于 SQLite 的可靠性 虽然语法看起来像是一个玩具库,但底层是成熟的 SQLite 引擎。这意味着你获得: - 事务支持(ACID) - 并发安全(多个进程可以同时读取) - 数据完整性(崩溃恢复) - 零外部依赖(SQLite 是 Python 标准库的一部分) ### 3. 轻量且可移植 整个库只有几百行代码,没有依赖其他第三方包(除了标准库)。数据库文件就是单个 `.db` 文件,可以轻松备份、迁移或嵌入到其他系统中。 ### 4. 动态属性映射的巧妙实现 SelfDB 通过重写 `__getattr__` 和 `__setattr__` 来拦截所有属性访问。当属性名以 `_` 开头时,它视为内部属性(如 `_connection`),否则视为用户数据。这种设计避免了与内部状态冲突,同时保持了 Python 的直观语法。 ### 5. 支持类型提示与默认值 你可以通过类属性定义默认值,SelfDB 会将其合并到读取逻辑中: python class MyDB(SelfDB): _defaults = { 'counter': 0, 'config': {'theme': 'dark'} } db = MyDB('app.db') print(db.counter) # 输出 0(默认值) db.counter += 1 # 修改后自动保存 ## 四、适用场景与真实用例 ### 场景 A:命令行工具的状态管理 写一个 CLI 工具,需要记住用户上次的选项、进度或缓存结果。用 SelfDB 只需要几行代码: python import click from selfdb import SelfDB state = SelfDB('cli_state.db') @click.command() @click.option('--verbose', is_flag=True) def main(verbose): if verbose: state.verbose = True else: # 读取上次的设置 verbose = getattr(state, 'verbose', False) click.echo(f'Verbose mode: {verbose}') ### 场景 B:Web 应用的轻量级会话存储 对于 Flask 或 FastAPI 的小型应用,不想引入 Redis 或数据库服务器时,SelfDB 可以作为会话存储的替代: python from flask import Flask, session from selfdb import SelfDB app = Flask(__name__) db = SelfDB('sessions.db') @app.route('/login') def login(): db.session_user = 'alice' return 'Logged in' @app.route('/profile') def profile(): user = db.session_user return f'Hello {user}' ### 场景 C:机器学习实验的配置与结果记录 在 Jupyter Notebook 或训练脚本中,记录超参数和评估指标: python from selfdb import SelfDB exp = SelfDB('experiment_1.db') exp.learning_rate = 0.001 exp.batch_size = 64 exp.accuracy = 0.934 # 后续分析时直接读取 ### 场景 D:嵌入式设备的配置持久化 在 Raspberry Pi 或 IoT 设备上,需要保存传感器校准值或设备ID,SelfDB 的轻量特性非常适合。 ## 五、与其他同类项目的对比 ### vs. SQLite 原生 + sqlite3 模块 - **SQLite 原生**:需要手动管理 SQL 语句、参数绑定、游标,代码量增加 5-10 倍。 - **SelfDB**:自动处理所有底层细节,但牺牲了复杂查询能力(如 JOIN、GROUP BY)。 ### vs. SQLAlchemy(Core/ORM) - **SQLAlchemy**:功能强大,支持多数据库、复杂关系、查询构建器,但学习曲线陡峭,配置繁琐。 - **SelfDB**:零学习成本,但仅支持键值对模式(属性名 → 值),不支持表关联、外键、索引优化。 ### vs. TinyDB - **TinyDB**:同样是纯 Python 的轻量级数据库,但需要定义 `Table` 和 `Document`,查询使用类 SQL 的语法。 - **SelfDB**:更极简,连表的概念都没有,整个数据库就是一个扁平的对象空间。TinyDB 支持更复杂的查询(`where` 条件),SelfDB 只支持属性名访问。 ### vs. shelve(标准库) - **shelve**:基于 dbm,只能存储 picklable 对象,不支持多线程写入,且没有 SQLite 的事务和崩溃恢复。 - **SelfDB**:基于 SQLite,更可靠,且数据文件可被其他 SQLite 工具(如 sqlite3 CLI)直接读取。 ### vs. Redis(内存数据库) - **Redis**:高性能网络服务,支持丰富的数据结构,但需要独立进程运行。 - **SelfDB**:本地文件,零部署,适合单机应用。 ## 六、局限性与注意事项 1. **不支持复杂查询**:如果你需要 `SELECT * FROM table WHERE age > 30` 这种条件过滤,SelfDB 不适合。它只适合通过属性名精确读写。 2. **性能瓶颈**:每次属性赋值都会触发磁盘写入(SQLite 默认同步模式)。对于高频写入场景(如每秒数百次),性能可能成为问题。可以通过 `PRAGMA synchronous = OFF` 调整,但会牺牲可靠性。 3. **无索引支持**:因为数据模型是扁平的键值对,无法为特定字段建立索引。 4. **并发写入限制**:SQLite 支持多进程读,但写操作会锁定整个数据库。SelfDB 没有实现任何锁机制,因此多进程并发写可能产生 `database is locked` 错误。 5. **类型安全性**:由于是动态属性,IDE 无法提供自动补全或类型检查。 ## 七、项目活跃度与社区 该项目由 fzakaria 开发,目前有 474 星,属于中等偏小众项目。Python 语言,代码仓库简洁,没有复杂的 CI/CD 或文档站。但核心代码质量不错,注释清晰,适合阅读源码学习元编程技巧。 ## 八、总结与推荐 **SelfDB 适合谁?** - 想快速持久化简单状态的 Python 开发者 - 不想引入重型 ORM 的小型项目 - 教学或演示场景(展示 Python 元编程之美) - 边缘计算、嵌入式设备上的配置存储 **SelfDB 不适合谁?** - 需要复杂查询、关系建模的应用 - 高并发写入场景 - 需要完整数据库管理(用户权限、备份恢复、迁移)的生产系统 如果你能接受它的局限性,SelfDB 会给你带来“写代码如行云流水”的体验。它把数据库的复杂度藏在了 Python 语言本身的语法糖之下,让你专注于业务逻辑而非数据存储细节。 > 项目链接:[https://github.com/fzakaria/selfdb](https://github.com/fzakaria/selfdb)
查看工具