ZODB 3中的PersistentSet

3 投票
3 回答
975 浏览
提问于 2025-04-15 11:39

ZODB 提供了一个叫 PersistentList 的东西和一个叫 PersistentMapping 的东西,但我想要一个 PersistentSet。于是我写了一个简单的类,模仿了 ZODB 2 里的古老 PersistentList。因为 Python 里没有 UserSet,所以我只能从 C 语言写的内置 set 继承。

class PersistentSet(UserSet, Persistent):
    def __iand__(self, other):
        set.__iand__(other)
        self._p_changed = 1

    ...

    ...

    ...

    def symmetric_difference_update(self, other):
        set.symmetric_difference_update(other)
        self._p_changed = 1

结果代码出现了一个“多个基类有实例布局冲突”的 错误。我尝试在 set 周围创建一个 UserSet 的包装,但这也没解决问题。

class UserSet(set):
    def __init__(self):
        self.value = set
    def __getattribute__(self, name):
        return self.value.__getattribute__(name

最后,我导入了 sets.Set(这个已经被内置的 set 替代了),但看起来这个也是用 C 实现的。我在 PyPI 上没有找到任何集合的实现,所以现在我陷入了困境。

我还有哪些选择呢? 我可能需要从头开始实现一个集合,或者使用 UserDict,然后把所有的 value 都扔掉。

3 个回答

1

为了将来阅读,我想提供一个对已经提出的答案的小改进...

自定义持久集合类

class PersistentSet(Persistent):

    def __init__(self, *args, **kwargs):
        self._set = set(*args, **kwargs)

    def __getattr__(self, name):
        return getattr(self._set, name)

库中的持久集合类

from BTrees.OOBTree import OOSet

另见

1

将所有属性请求转发到内部设置:

class PersistentSet(Persistent):
    def __init__(self):
        self.inner_set = set()

    def __getattribute__(self, name):
        try:
            inner_set = Persistent.__getattribute__(self, "inner_set")
            output = getattr(inner_set, name)
        except AttributeError:
            output = Persistent.__getattribute__(self, name)

        return output
3

为什么不使用ZODB中提供的持久集合类呢?在这里有四个这样的类。IITreeSet和IOTreeSet用来管理整数集合,而OITreeSet和OOTreeSet则用来管理任意对象的集合。它们分别对应四个BTree类:IIBTree、IOBTree、OIBTree和OOBTree。相比于Python内置的集合实现,这些类的优势在于它们有更快的查找机制(这要归功于底层的BTree)以及持久化支持。

下面是一些示例代码:

>>> from BTrees.IIBTree import IITreeSet, union, intersection
>>> a = IITreeSet([1,2,3])
>>> a
<BTrees._IIBTree.IITreeSet object at 0x00B3FF18>
>>> b = IITreeSet([4,3,2])
>>> list(a)
[1, 2, 3]
>>> list(b)
[2, 3, 4]
>>> union(a,b)
IISet([1, 2, 3, 4])
>>> intersection(a,b)
IISet([2, 3])

撰写回答