4

If I had a list of some python class that had a string field, is there a way to compare a string to a list of objects of that class using in? I was curious if there's a way to do something like this:

class Foo:
    def __init__(self, s):
        self.s = s

bar = Foo('test')
ls = [bar]

if 'test' in ls:
    print("Yay!")

by modifying the __eq__ method, or maybe even there's an __in__ method I'm unaware of

Mazdak
  • 105,000
  • 18
  • 159
  • 188
Zaya
  • 316
  • 4
  • 14

2 Answers2

3

You intuition about defining a custom __eq__ was right. You can achieve the following, which seems to be your objective here:

>>> class Foo:
...     def __init__(self, s):
...         self.s = s
...     def __eq__(self, other):
...         if isinstance(other, Foo):
...             return self.s == other.s
...         else:
...             return self.s == other
...
>>>
>>> bar = Foo('bar')
>>> l = [bar]
>>> bar in l
True
>>> 'bar' in l
True
>>> Foo('baz') in l
False
>>> 'baz' in l
False

I also want to point out that there is the __contains__ method, which allow you to define the membership operator's behavior (in). However this is a method on the container type, so here defining this method for your class Foo wouldn't do anything, since the in is applied to the list, and not its individual items.

Samuel Dion-Girardeau
  • 2,790
  • 1
  • 29
  • 37
  • The isinstance() method is key here, I didn't know you could do that! My class works like a dream now – Zaya May 15 '18 at 15:56
  • Glad to help! Note that `isinstance(bar, Foo)` is more robust than `bar.__class__ == Foo`, because it also works for subclasses of `Foo`. – Samuel Dion-Girardeau May 15 '18 at 15:58
  • 1
    I don't think if there's a need to use `isinstance(bar, Foo)` because once the equation check for one side of the equation fails Python will call the other side's `__eq__`. – Mazdak May 15 '18 at 16:03
2

Your guess about modifying the __eq__ is correct. It's definitely one way to do this. You just need to check the value of __eq__'s argument with the respective attribute of your object. So as a very simple way you can implement something like following:

In [1]: class Foo:
   ...:     def __init__(self, s):
   ...:         self.s = s
   ...:
   ...:     def __eq__(self, value):
   ...:         return self.s == value
   ...:     

In [2]: bar = Foo('test')
   ...: ls = [bar]
   ...: 

In [3]: 'test' in ls
Out[3]: True

Note that this __eq__ method doesn't have any restrictions like type checking or some other error handling. If you think that they're needed in your case you can consider using try-excep and or other condition checking as well.

Demo:

In [9]: foo = Foo('test')

In [10]: bar = Foo('test')

In [11]: ls = ['test']

In [12]: bar in ls
Out[12]: True

In [13]: ls = [bar]

In [14]: foo in ls
Out[14]: True
Mazdak
  • 105,000
  • 18
  • 159
  • 188