我正在寻找一种方法来管理一组 Python 数据结构,这些数据结构可以很好地融入关系模式,但没有真正的数据库或解析 SQL 的开销。可以假设数据量足够小以方便地放入内存(例如,没有结构包含超过一百万个元素)。
最重要的是,我想自动强制执行外键约束。在违反外键约束时触发断言失败就足够了;它总是一个编程错误。
这是我想要完成的真实示例。我确实有执行此操作的代码,但是如果没有自动外键约束检查,它会变得容易出错并且断言混乱。
(这些是代码的数据结构,用于分析机器代码程序的执行跟踪,出于好奇。记录器程序将每个唯一的 (previous_instruction_addr, current_instruction_addr, stack_pointer_change) 元组输出一次。)
instrs
: set(int) (看到的机器指令的地址)next_instrs
: dict(int -> set(int)),一个字典,将一条指令(必须在 ininstrs
)映射到一组指令(所有指令都必须在 ininstrs
)。从关系上讲,是instrs
×的一个子集instrs
。stk_changes
: dict((int,int) -> set(int)),一个字典,映射一对指令(这对指令必须在其中next_instrs
)到堆栈指针寄存器中的一组变化jumps
: set((int,int)),next_instrs
关系的子集,被认为是从一条指令到另一条指令的跳转(包括函数调用或函数返回)。实际上,我目前将其实现为两个字典,因为我需要能够以“这条指令在哪里跳转?”的形式进行查询。和“什么指令跳转到这个指令?”。calls
: set((int,int)),其中的一个子集jumps
是函数调用。rets
: set((int,int)),其中的一个子集jumps
是函数的返回值。basic_blocks
: set(int), 的子集instrs
;基本块的第一个地址(执行只从第一条指令开始的代码块,即没有跳转到中间,并且只在最后一条指令结束,即没有从中间跳转)containing_bb
: dict(int -> int),包含每条指令的基本块。instrs
×的子集basic_blocks
functions
: set(int), 被认为是函数开始的基本块。的一个子集basic_blocks
。function_calls_by_bb
: dict(int -> int),由基本块调用的函数;basic_blocks
×的子集functions
等等; 你明白了。
我本质上要寻找的是一种管理所有这些结构并自动执行所有外键约束的方法;例如,basic_blocks.add(something)
如果something
不是instrs
. 同样,basic_blocks.remove(something)
如果something
仍然由function_calls_by_bb
. 显然,与例如 SQL 数据库模式中的外键约束相比,为所有这些结构编写断言add()
和remove()
方法是不必要的冗长且容易出错。
我目前正在使用带有内存中 sqlite 数据库的 sqlalchemy,这让我能够以一种很好的方式描述约束,但理想情况下,我正在寻找不涉及数据库引擎的更轻量级的东西。(可能是数据库引擎最终是做我正在做的事情的正确方法,但目前我正在评估替代方案。)
或者,如果你能想到其他方法来管理这样的结构,我也有兴趣了解这些。