12.4. Operators Comparison

12.4.1. Rationale

Table 12.3. Comparison Operators Overload

Operator

Method

obj == other

obj.__eq__(other)

obj != other

obj.__ne__(other)

obj < other

obj.__lt__(other)

obj <= other

obj.__le__(other)

obj > other

obj.__gt__(other)

obj >= other

obj.__ge__(other)

12.4.2. Object Equality

>>> class Astronaut:
...     firstname: str
...     lastname: str
...
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> b = Astronaut('Mark', 'Watney')
>>>
>>> a == b
False
>>>
>>> hex(id(a))  
'0x11b9706a0'
>>> hex(id(b))  
'0x11b970700'
>>> id(a) == id(b)
False
>>> class Astronaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __eq__(self, other):
...         return (self.firstname == other.firstname) \
...            and (self.lastname == other.lastname)
>>>
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> b = Astronaut('Mark', 'Watney')
>>>
>>> print(a == b)
True
>>>
>>> hex(id(a))  
'0x11b970c70'
>>> hex(id(b))  
'0x11b9704c0'
>>> id(a) == id(b)
False

12.4.3. Problem

  • When you compare objects with the same fields from two different classes

>>> class Astronaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __eq__(self, other):
...         return (self.firstname == other.firstname) \
...            and (self.lastname == other.lastname)
>>>
>>>
>>> class Cosmonaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> c = Cosmonaut('Mark', 'Watney')
>>>
>>> print(a == c)
True

12.4.4. Solution

  • Always remember to compare classes

  • This way you avoid bug, when both has the same fields and values

>>> class Astronaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __eq__(self, other):
...         return (self.__class__ is other.__class__) \
...            and (self.firstname == other.firstname) \
...            and (self.lastname == other.lastname)
>>>
>>>
>>> class Cosmonaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> c = Cosmonaut('Mark', 'Watney')
>>>
>>> print(a == c)
False

12.4.5. Eq Works at Both Sides

>>> class Astronaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __eq__(self, other):
...         return (self.firstname == other.firstname) \
...            and (self.lastname == other.lastname)
>>>
>>>
>>> class Cosmonaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> c = Cosmonaut('Mark', 'Watney')
>>>
>>> print(a == c)
True
>>> class Astronaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> class Cosmonaut:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __eq__(self, other):
...         return (self.firstname == other.firstname) \
...            and (self.lastname == other.lastname)
>>>
>>>
>>> a = Astronaut('Mark', 'Watney')
>>> c = Cosmonaut('Mark', 'Watney')
>>>
>>> print(a == c)
True

12.4.6. Use Case - Game

>>> hero < Damage(20)  
>>> hero > Damage(20)  

12.4.7. Assignments

Code 12.25. Solution
"""
* Assignment: Operators Comparison Equals
* Complexity: easy
* Lines of code: 3 lines
* Time: 5 min

English:
    1. Override operator for code to work correctly
    2. Do not use `dataclasses`
    3. Run doctests - all must succeed

Polish:
    1. Nadpisz operator aby poniższy kod zadziałał poprawnie
    2. Nie używaj `dataclasses`
    3. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> Mission(2035, 'Ares 3') == Mission(2035, 'Ares 3')
    True
    >>> Mission(2035, 'Ares 3') == Mission(1973, 'Apollo 18')
    False
    >>> Mission(2035, 'Ares 3') == Mission(2035, 'Apollo 18')
    False
    >>> Mission(2035, 'Ares 3') == Mission(1973, 'Ares 3')
    False
"""

class Mission:
    def __init__(self, year, name):
        self.year = year
        self.name = name