title: How to make a hashable and comparable custom object with mutable fields in Python?
body: <p>I want to define a hashable class with mutable fields, but if I define the <code>__eq__</code> method myself (which definitely I want to do), it is no longer hashable by default and I need to define <code>__hash__</code> method as well.</p>
  
  <p>If I define the <code>__hash__</code> method such that it just compares the <code>id()</code> values like it (I think) did by default before I defined <code>__eq__</code> I get weird results.</p>
  
  <p>According to <a href="https://stackoverflow.com/questions/2040101/using-object-id-as-a-hash-for-objects-in-python">this question</a>, I have to define <code>__eq__</code> the same way as <code>__hash__</code> but I would like to understand why this is the case and, if possible, how to work around that.</p>
  
  <p>To be specific, I want to define objects with two mutable fields containing integers:</p>
  
  <pre><code>class CustomObj:
      def __init__(self, a, b):
          self.a = a
          self.b = b
  
  ObjA = CustomObj(1, 2)
  ObjB = CustomObj(1, 2)
  </code></pre>
  
  <p>I want to be able to compare them to each other <code>ObjA == ObjB</code>, as well as to simple tuples <code>ObjA == (1, 2)</code>. I also want to be able to store them in a set <code>myset = set()</code>, so that I can check both <code>(1, 2) in myset</code> and <code>ObjA in myset</code> for the same result. How can I achieve this?</p>
  
  <p>This is my code at the moment, but it's definitely not behaving correctly:</p>
  
  <pre><code>class Agent:
      def __init__(self, x, y):
          self.x = x
          self.y = y
  
      def __eq__(self, other):
          try:
              # Try comparing two agents
              return (self.x == other.x and self.y == other.y
                          and isinstance(other, Agent))
          except AttributeError:
              # If it fails, compare an agent and a tuple
              if isinstance(other, tuple) and len(other) == 2:
                  return self.x == other[0] and self.y == other[1]
              else:
                  return NotImplemented
  
      def __hash__(self):
          return id(self)
  </code></pre>