使用slots比较Python类的等价性

8 投票
2 回答
1672 浏览
提问于 2025-04-16 08:58

另一个问题提供了一个简单好用的方法来检查对象是否相等。我在这里重复一下这个答案,以便大家理解:

class CommonEqualityMixin(object):

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

    def __ne__(self, other):
        return not self.__eq__(other)

class Foo(CommonEqualityMixin):

    def __init__(self, item):
        self.item = item

我想在一个使用了__slots__的类中实现这个功能。我知道基类和子类都需要使用slots,但我该如何为这个类定义__eq__,才能让它和slots一起正常工作呢?

2 个回答

1

杰夫,如果你需要跟踪这么多记录,建议你考虑使用“享元”设计模式。

可以参考这个链接:http://codesnipers.com/?q=python-flyweights

这个页面讲述了一种情况,很多被跟踪的记录有相同的值。在这种情况下,享元模式非常有用。不过,即使记录的值基本上是独一无二的,这个模式也同样适用。比如,你可以把这些值存储在一个numpy数组或矩阵里,然后用一个类来封装这些存储。

11
import operator

class CommonEqualityMixin(object):

    __slots__ = ()

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            if self.__slots__ == other.__slots__:
                 attr_getters = [operator.attrgetter(attr) for attr in self.__slots__]
                 return all(getter(self) == getter(other) for getter in attr_getters)

        return False

    def __ne__(self, other):
        return not self.__eq__(other)

使用示例:

class Foo(CommonEqualityMixin):
    __slots__ = ('a', )
    def __init__(self, a):
        self.a = a

Foo(1) == Foo(2)
# False
Foo(1) == Foo(1)
# True

注意:要知道 __slots__ 是不会被继承的,这和 __dict__ 不一样。所以如果比如说一个新类 FooBar 继承自 Foo,上面的代码就不管用了。

示例:

class FooBar(Foo):
    __slots__ = ('z')
    def __init__(self, a, z):
        self.z = z
        super(FooBar, self).__init__(a)

FooBar(1, 1) == FooBar(2, 1)
# True

print FooBar(1, 1).__slots__
# 'z'

撰写回答