6

suppose I have a class:

class Cat:
    def __init__(self, name = "default", age = 0):
        self.name = name
        self.age = age

I also have a list of Cats:

l = [Cat('Joe')]

Now I can't call the following:

if 'Joe' in l: # the right syntax would be if Cat('Joe') in list

Which operator do I need to overload to be able to identify objects of class Cat by their member variable name?

gen
  • 9,528
  • 14
  • 35
  • 64
  • 1
    I guess its the equal operator, where you can check if the other object is of the same instance and it's name property matcheses the current object's name: `__eq__(self, other): #todo check if other is ame type and if name matches self.name` Defines behavior for the equality operator, ==. Sorry, I am a C# guy... – Bernhard Kircher Aug 13 '13 at 13:34

2 Answers2

7

You have to define the __eq__ method, as shown below:

class Cat:

    def __init__(self, name = "default", age = 0):
        self.name = name
        self.age = age

    def __eq__(self, other):
        if isinstance(other, str):
            return self.name == other
        elif isinstance(other, Cat):
            return self.name == other.name

So that when you run your check:

l = [Cat('Joe')]

'Joe' in l
#True
gen
  • 9,528
  • 14
  • 35
  • 64
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • 3
    OP should define `__hash__()` as well so that it works with sets/dicts. See [the data model documentation](http://docs.python.org/2.7/reference/datamodel.html). – Daniel Roseman Aug 13 '13 at 13:35
  • I am sorry, what does isinstance? Why do u need that if statement? – gen Aug 13 '13 at 13:37
  • @gen in this case `isinstance` checks if `other` is a string (`str`) or another `Cat`, to tell `__eq__` what to do in each case... – Saullo G. P. Castro Aug 13 '13 at 13:38
  • I have another question: If I do the following: `for catname in l: print catname` What would it print the object of class Cat or only the name of the object? – gen Aug 13 '13 at 13:45
  • to print the object you can define `__str__()` as [explained here](http://stackoverflow.com/a/1535336/832621) – Saullo G. P. Castro Aug 13 '13 at 13:47
2

__contains__ on list objects is implemented by checking for equality, so override __eq__:

class Cat:
    def __init__(self, name = "default", age = 0):
        self.name = name
        self.age = age
    def __eq__(self, other):
        return self.name == other

This works irrespective of ordering because equality checking swaps its arguments when the left side does not support the operation.

If you want it to work with hash-based containers (e.g. set, dict) you'll have to override __hash__ as well:

    def __hash__(self):
        return hash(self.name)
ecatmur
  • 152,476
  • 27
  • 293
  • 366