笔记
0工具
0此页用于记录用户反馈问题后的每一次改进
关于
“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。
md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。
要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。
在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。
要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。
工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。
写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。
适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。
不想公开、只想临时给人看:点“分享”生成一条带密码和有效期的链接,到期自动失效,你也能随时撤销。
你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。
全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。
这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。
不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。
产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。
如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。
趋势
selfdb:把整个Python程序变成可查询数据库的魔法库
selfdb 是一个将 Python 程序运行时状态自动暴露为 SQL 可查询数据库的开发工具,让你用 SQL 直接查询内存中的对象、函数调用和变量。
痛点:调试和观测 Python 程序为何如此痛苦
在开发 Python 应用时,我们经常面临这样的困境:
- 调试复杂状态:当程序运行到某个分支时,你想知道当前所有模块的全局变量、某个对象的属性、甚至最近几次函数调用的参数——但只能靠
print或pdb手动断点,效率低下。 - 事后分析:程序崩溃后,你想复盘“当时发生了什么”,但日志不够详细,回放困难。
- 性能分析:你想知道某个函数被调用了多少次、平均耗时多少,通常需要引入
cProfile或手动埋点。 - 动态数据探索:你希望像操作数据库一样,用
SELECT和JOIN去探索程序内部的数据关系,但 Python 对象图是任意复杂的,没有统一查询接口。
传统方案要么是侵入式埋点(污染业务代码),要么是外部调试器(无法访问运行时上下文),要么是日志分析(丢失对象结构)。selfdb 提出一个全新的思路:把整个 Python 进程变成一台数据库服务器,你可以在程序运行的同时,用 SQL 查询它的内部状态。
selfdb 是什么
selfdb 是一个纯 Python 库,它通过 sys.settrace 钩子自动捕获程序执行过程中的所有帧(frame)、局部变量、全局变量、函数调用和返回值,并将它们组织成一张张关系表。然后,它启动一个内置的 SQLite 虚拟数据库(通过 sqlite3 的虚拟表机制),让外部客户端(如 sqlite3 命令行、Python sqlite3 模块、甚至其他语言的 SQLite 驱动)直接连接并查询这些表。
简单说:你的程序运行到一半,你可以用 SQL 去查询它现在的内存状态。
快速上手
安装
bash
pip install selfdb
最小示例:查询全局变量
python
import selfdb
import threading
import time
启动 selfdb,监听在本地 12345 端口(默认)
selfdb.start(port=12345)
程序正常运行
counter = 0
def worker():
global counter
for i in range(100):
counter += 1
time.sleep(0.01)
threads = [threading.Thread(target=worker) for _ in range(5)]
for t in threads:
t.start()
保持程序运行,等待外部查询
selfdb.wait() # 阻塞,直到 Ctrl+C
在另一个终端,用任意 SQLite 客户端连接:
bash
sqlite3 selfdb.db
或者通过 Python 连接:
python
import sqlite3
conn = sqlite3.connect('selfdb.db')
查看有哪些表
print(conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall())
查询全局变量 counter 的当前值
rows = conn.execute("SELECT * FROM globals WHERE name='counter'").fetchall()
print(rows)
你会发现 globals 表中有当前所有全局变量的名称、类型和值。更神奇的是,你可以实时查询——每次 SELECT 都会获取最新状态。
查询函数调用历史
selfdb 会自动记录每次函数调用的参数和返回值,存到 calls 表:
sql
SELECT function_name, args, return_value, duration_ms
FROM calls
ORDER BY timestamp DESC
LIMIT 10;
你可以看到最近 10 次函数调用的完整记录,包括参数值、返回值和耗时。这对于调试性能瓶颈和异常流程非常有用。
查询局部变量和帧信息
selfdb 还记录了每个活动线程的调用栈(stack frames)。你可以查询 frames 表:
sql
SELECT thread_id, filename, lineno, function, locals_json
FROM frames
WHERE thread_id = 5;
locals_json 是该帧的所有局部变量序列化后的 JSON 字符串。这样,你可以看到某个线程当前执行到哪一行,局部变量是什么。
核心亮点:深入技术细节
1. 基于 sys.settrace 的零侵入捕获
selfdb 利用 Python 的追踪钩子(sys.settrace)在每次函数调用、行执行、返回时触发回调。它不修改你的源代码,也不要求你显式地记录任何数据。你只需要 import selfdb; selfdb.start(),剩下的自动完成。
需要注意的是,sys.settrace 本身会带来一定的性能开销(通常 20%-50%),所以 selfdb 更适合开发调试和测试环境,不适合生产环境长期开启。但它的设计允许你通过环境变量或命令行参数动态开启/关闭,例如:
bash
SELFDB_ENABLED=1 python my_app.py
2. 虚拟表:SQLite 与 Python 对象的桥梁
selfdb 没有把数据复制到 SQLite 文件,而是通过 SQLite 的虚拟表机制(sqlite3 模块中的 create_module)动态生成查询结果。每次你执行 SELECT,它都会实时从 Python 的内存中提取数据并返回。这意味着:
- 数据永远是最新的:你看到的就是程序此刻的状态。
- 无持久化开销:不需要写文件,不占用磁盘。
- 支持复杂 SQL:你可以对查询结果进行
WHERE、JOIN、GROUP BY等操作,因为虚拟表的行为和普通表一样。
3. 支持多线程和异步
selfdb 能正确区分不同线程的帧和局部变量。对于 asyncio 协程,它也能捕获事件循环中的任务状态(通过钩住 asyncio.Task 的创建和切换)。
4. 安全性和访问控制
默认只监听 127.0.0.1,避免远程访问风险。你可以通过 selfdb.start(host='0.0.0.0') 开启远程,但需要自己加认证(建议通过 SSH 隧道)。
5. 可扩展的表结构
除了内置的 globals、locals、frames、calls 表,selfdb 还提供 objects 表,让你按类名查询所有实例:
sql
SELECT class_name, id, repr, attributes_json
FROM objects
WHERE class_name = 'MyClass';
这会遍历 gc.get_objects() 找到所有 MyClass 的实例,并序列化它们的属性。
适用场景
- 复杂算法调试:比如图算法、动态规划,你想在每一步检查中间状态,用 SQL 比用
print更灵活。 - Web 服务开发:在 Flask/Django 开发中,你可以开启 selfdb,然后通过 SQL 查询当前请求的上下文、数据库连接池状态、缓存命中率等。
- 数据分析脚本:你在 Jupyter 中运行长任务,想中途查看某个变量的分布,直接用 SQL 查询。
- 教学演示:向学生展示 Python 程序内部执行过程,用 SQL 查询帧和变量,直观且有趣。
- 自动化测试:在测试框架中,你可以用 selfdb 断言某个函数被调用了多少次、参数是否正确,而不用 mock。
与其他工具对比
| 工具 | 定位 | 与 selfdb 的区别 |
|---|---|---|
pdb/ipdb |
交互式调试器 | 需要手动打断点,只能查看当前帧,不能跨线程/跨时间查询。selfdb 提供全局、实时的 SQL 接口。 |
py-spy |
采样性能分析器 | 只给出 CPU 火焰图,无法查询变量值。selfdb 能给出具体数据。 |
tracemalloc |
内存跟踪 | 只关注内存分配,不提供业务对象状态。 |
logging |
日志记录 | 需要手动埋点,且日志是文本流,无法结构化查询。selfdb 自动捕获所有调用和变量。 |
django-debug-toolbar |
Web 调试面板 | 只适用于 Django,且只显示 SQL 查询和请求信息,不能查询任意 Python 对象。 |
ipython 的 %debug |
事后调试 | 只能在异常后进入,不能实时查询。 |
selfdb 的核心差异化在于:它把调试从“断点思维”转变为“数据库思维”。你不再需要关心“停在哪一行”,而是可以随时问“现在全局有哪些对象?它们之间的关系是什么?”
局限性与注意事项
- 性能开销:开启追踪后,程序运行速度会明显下降,不适合生产环境。
- 序列化限制:某些对象(如生成器、socket、线程锁)无法被序列化为 JSON,selfdb 会用其
repr字符串代替。 - 安全性:暴露了程序内部所有数据,切勿在不可信网络下开启远程连接。
- Python 版本:目前支持 CPython 3.7+,不兼容 PyPy 或 Jython(因为
sys.settrace行为差异)。
总结
selfdb 是一个极具创意的开发工具,它模糊了“程序运行”和“数据库查询”的边界。虽然它可能不会成为生产环境中的常驻工具,但在开发、调试、测试和教学场景中,它提供了一种全新的、高效的交互方式。如果你厌倦了 print 和断点调试,不妨试试用 SQL 来“审视”你的程序。