有没有简单的方法在不重新定义所有运算符的情况下子类化Python的集合?

1 投票
2 回答
58 浏览
提问于 2025-04-13 01:37

有没有办法去创建一个新的类,基于 set 这个集合类型,并且在使用二元运算符时返回这个新类的类型,而不需要重新定义这些运算符?

举个例子:

class A(set):
    pass

a = A([1,2,3]) & A([1,2,4])


a.__class__ == A # it's False, and I would like it to be true without redefining all operators

注意,这个问题:如何正确(或最佳)地创建一个新的 Python 集合类,并添加一个新的实例变量? 已经有10年了,提供的答案只适用于 Python 2.x。这就是我为什么要问一个关于 Python 3.x(特别是 Python ≥ 3.8)的新问题。

2 个回答

1

看起来你确实需要重新定义一些集合方法,但只需要重新定义那些返回set对象的方法,这一共只有13个方法,而且这些方法的代码都是模板代码。

下面是一个例子:

class ASet(set):
    def __repr__(self):
        return f'ASet({set(self)})'

    def __and__(self, other):
        return self.__class__(super().__and__(other))

    def __or__(self, other):
        return self.__class__(super().__or__(other))

    def __rand__(self, other):
        return self.__class__(super().__rand__(other))

    def __ror__(self, other):
        return self.__class__(super().__ror__(other))

    def __rsub__(self, other):
        return self.__class__(super().__rsub__(other))

    def __rxor__(self, other):
        return self.__class__(super().__rxor__(other))

    def __sub__(self, other):
        return self.__class__(super().__sub__(other))

    def __xor__(self, other):
        return self.__class__(super().__xor__(other))

    def copy(self, other):
        return self.__class__(super().copy(other))

    def difference(self, other):
        return self.__class__(super().difference(other))

    def intersection(self, other):
        return self.__class__(super().intersection(other))

    def symmetric_difference(self, other):
        return self.__class__(super().symmetric_difference(other))

    def union(self, other):
        return self.__class__(super().union(other))

3

我认为答案是“没有”。

我快速浏览了一下参考实现,发现对于 set_and() 的所有路径,最终都返回 NULL 或者调用 make_new_set_basetype() 的结果。

这个方法目前是 这样实现的

make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
{
    if (type != &PySet_Type && type != &PyFrozenSet_Type) {
        if (PyType_IsSubtype(type, &PySet_Type))
            type = &PySet_Type;
        else
            type = &PyFrozenSet_Type;
    }
    return make_new_set(type, iterable);
}

所以,如果你没有在子类中重写 __and__(),你得到的结果将是一个 set() 或者一个 frozenset()

撰写回答