2

What magic method do I have to modify to support the in operator. Here's an example of what I'm trying to do:

class DailyPriceObj:
    def __init__(self, date, product_id=None):
        self.date = date
        self.product_id = product_id
        self.sd_buy = None

l = list()
l.append(DailyPriceObj(date="2014-01-01"))
DailyPriceObj(date="2014-01-01") in l # how to get this to return True?

In other words, I want my object to "act like" the date property, so I can use that to see if that obj is in an interable (date should be a unique field here).

David542
  • 104,438
  • 178
  • 489
  • 842
  • @DanielMesejo no I've updated the question to make this more clear. – David542 Oct 10 '19 at 19:41
  • The problem is that you cannot do both, `DailyPriceObj(date="2014-01-01") == DailyPriceObj(date="2014-01-01")` and `"2014-01-01" in l` because `"2014-01-01" in l == True` implies `DailyPriceObj(date="2014-01-01") == "2014-01-01"`. At least in my opinion – Dani Mesejo Oct 10 '19 at 19:45
  • @David542 you can define eq base on date, but you, at least, need to check type of other. In your case for type(other) == datetime . In other words, DailyPriceObj(date="2014-01-01") == datetime("2014-01-01") – splash58 Oct 10 '19 at 19:45
  • Does this answer your question? [Override Python's 'in' operator?](https://stackoverflow.com/questions/2217001/override-pythons-in-operator) – AMC Feb 08 '20 at 02:13

2 Answers2

5

You need to implement __eq__ (and __hash__ for the sake of completeness):

class DailyPriceObj:
    def __init__(self, date, product_id=None):
        self.date = date
        self.product_id = product_id
        self.sd_buy = None

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

    def __hash__(self):
        return hash(self.date)


l = [DailyPriceObj(date="2014-01-01")]
s = {DailyPriceObj(date="2014-01-01")}

print(DailyPriceObj(date="2014-01-01") in l)
print(DailyPriceObj(date="2014-01-01") in s)

Output

True
True

From the documentation on __hash__:

Called by built-in function hash() and for operations on members of hashed collections including set, frozenset, and dict. __hash__() should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to mix together the hash values of the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple.

Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
  • Thanks for the clarification -- is the only reason to use the `hash()` function so that it's cast into an `int`? Otherwise, couldn't you just return `self.date` in the `__hash__`? – David542 Oct 10 '19 at 19:56
  • Yes, and also because the hash of your object is based on the hash of self.date – Dani Mesejo Oct 10 '19 at 19:57
1

You can implement __eq__ in such a way that both two ways of checking will work:

class DailyPriceObj:
    def __init__(self, date, product_id=None):
        self.date = date
        self.product_id = product_id
        self.sd_buy = None

    def __eq__(self, other):
        return self.date == other

l = list()
l.append(DailyPriceObj(date="2014-01-01"))
# both ways work:
print(DailyPriceObj(date="2014-01-01") in l)  # True
print("2014-01-01" in l)  # True
sanyassh
  • 8,100
  • 13
  • 36
  • 70