8

Another question provides a nice, simple solution for implementing a test for equality of objects. I'll repeat the answer for context:

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

I would like to do this for a class that uses __slots__. I understand that both the base class and the subclass will have to use slots, but how would you define __eq__ for this to work with slots?

Community
  • 1
  • 1
new name
  • 15,861
  • 19
  • 68
  • 114

2 Answers2

10
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)

An example of usage:

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

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

N.B: be aware thow the __slots__ don't get inherited it's not like __dict__ so if for example a new class FooBar inherit from Foo the code above will not work

Example :

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'
mouad
  • 67,571
  • 18
  • 114
  • 106
  • the method above is just to give you some idea , it have some problem like if "__slots__" is a string !!! well i think you will find some problems when working with "__slots__" you can find a lot of people that don't advise the use of "__slots__" , so i will advise you to ask your self before using them if it's worth the effort !!! Hope this can help :) – mouad Dec 23 '10 at 22:28
  • 1
    Thanks! That is a nice answer. I will reconsider using slots as you suggest, but since I am creating one million instances of this class it is probably worthwhile. – new name Dec 24 '10 at 16:03
  • A rather old answer... but still, what's the solution for your `FooBar` example at the end? (inheritance) – Guy Sep 08 '16 at 11:27
1

Jeff, you should consider using the Flyweight design pattern if you need to track that many records.

See: http://codesnipers.com/?q=python-flyweights

That page describes a situation in which many of the tracked records have identical values. In that case, the Flyweight pattern is extremely useful. However, it is also very useful when the records have effectively unique values. (in which case you store the values in a numpy array/matrix, etc. and wrap the storage in a class).

John Prior
  • 1,508
  • 1
  • 16
  • 19