Python has two very similar comparison operators: == for equality and is for object identity. Typically, is faster, as the implementation just needs to compare object ids, whereas == must call the eq method, and is therefor slower.

The operator is is recommended for comparisons with None in Python (as in if a is None). And I was asking myself how much overhead the == method would be in this case. So I figured that the None == None case might be more efficient, than the generic a == None case, because the runtime could first check for identity before deciding to call eq.

As it happens, Python has strange semantics with respect to these operators, and my assumption was wrong. I was assuming that a == a was always True (since a is a is True, and identity should imply equality). This is, however, not the case:

>>> class A:
...     def *eq*(self, rhs):
...         return False :

>>> a = A()

>>> a == a
False

(tested with Python 3.5).[multiblock footnote omitted]

I haven’t found https://docs.python.org/3/reference/datamodel.html?highlight=eq#object.eq[much in the Python docs] about this, but I guess that someone has a use case where a==a should evaluate to false, although objects are identical. Another explanation would be that if eq would have a side-effect, it should be called in any case, even for identical objects. Right now, I cannot think of any cases where either of these options would be desirable. So if you stumble over classes where a == a does not evaluate to True it might be worth investigating.

Footnotes

Ruby

Ruby does not do it any other way. I find it a bit less surprising, here, as we direcly overwrite the == operator that is called later, instead of Python’s approach of using a protocol method eq:

irb(main):001:0> class A
irb(main):002:1>     def ==(rhs)
irb(main):003:2>         false
irb(main):004:2>     end
irb(main):005:1> end
irb(main):011:0> a = A.new
=> #<A:0x007fda8190f2c8>
irb(main):013:0> a == a
=> false
irb(main):015:0> a === a
=> true