0

If the Python name x in Python refers to an immutable value, would these two statements return the same result and do an equivalent / identical check?

x is None vs x == None

I couldn't find an exact duplicate of this question, but perhaps it's still answered implicitly elsewhere, but here are some related questions:

Josh
  • 11,979
  • 17
  • 60
  • 96
  • `None` is a singleton so I'm not sure where mutability comes into this – roganjosh Apr 25 '20 at 17:43
  • `is` and `==` never do an identical check. The former returns True if its arguments refer to the same object. The latter calls the magic method `__eq__` which can be overridden. – Mark Tolonen Apr 25 '20 at 17:48

1 Answers1

2

It has nothing to do with the immutability of x. None is a singleton for which is and == return identical results, unless the type of x defines a weird __eq__ method. The name x is either bound or not bound to the same object as None. If not, the identity check will always be False, regardless of what other type it is. The result of the equality check is up to the type of x, but will be the same as the identity check for most sane classes.

Now the caveat is that while you can't override is, since that's an identity check done by the interpreter, you can override ==. Aside from speed and consistency, here's a toy example showing why x is None is preferable to x == None:

class Test:
    def __eq__(self, other):
        if other is None:
            return True
        return self is other
>>> Test() == None
True
>>> None == Test()
True
>>> Test() is None
False
>>> None is Test()
False

The reason that both Test () == None and None == Test() return the same result has to do with how comparisons are evaluated, and the fact that None does not define an explicit __eq__ method. Normally, the interpreter calls type(left).__eq__(left, right) on the operands. If the left operand's type does not define __eq__ or the method returns NotImplemented, it attempts type(right).__eq__(right, left). Only if both fail does it fail over to a built-in identity check. Since None doesn't define an equality check, it will always use the check defined by the other object before failing over to the identity check.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Got it, perfectly clear. Thanks! – Josh Apr 25 '20 at 19:26
  • I don't see how your example demonstrates that `x is None` is preferable to `x == None`. Yes, I see that they behave differently on this example-- the former yields False and the latter yields True. So you're saying False is the preferable answer? I don't see it. In fact, it seems to me that True is preferable, since that seems to be the behavior this Test class is intending to implement. – Don Hatch Apr 13 '23 at 10:57
  • @DonHatch where did you get the idea that either approach is preferable? OP asked about the differences, and the answer clearly describes those. The idea is that you pick the approach you want based on your needs and those differences. – Mad Physicist Apr 13 '23 at 11:28
  • @DonHatch. The example is contrived and unlikely to be practical. However, as you correctly noted, the correct answer is what you want it to be – Mad Physicist Apr 13 '23 at 11:54
  • Regarding "where did you get the idea that either approach is preferable?" Didn't you say it? :-) I'm specifically responding to this in your answer: "here's a toy example showing why x is None is preferable to x == None". In any case, I have yet to understand why the semantics of "is None" would ever be preferred, and why PEP8 asks that we memorize and use this apparently useless idiom. – Don Hatch Apr 13 '23 at 21:27
  • @DonHatch. Because None is a singleton specifically made to be compared by identity. `==` should be used when you can have multiple objects that have the same value, like an `int` or `float`, which can be identical without occupying the same memory. There is literally only one `None` object ever in existence in a given interpreter execution, and comparing with `is` is much faster than with `==`. – Mad Physicist Apr 13 '23 at 21:51
  • @DonHatch. You're right, I did say that `is` is better here. I skimmed the answer and did not notice that originally. I claim that `is None` is better exactly because `None` is a singleton that is semantically expected to be equal only to itself. The toy example violates expectation, which is bad in python. – Mad Physicist Apr 13 '23 at 21:59
  • @MatPhysicist Thanks. However, True, False, and ints in the range -5 to 256 (or so) are also singletons, if I understand correctly, all of these facts being unimportant implementation details of python, as far as I can see. So, should all of these be compared by "is" as well, for the same reason? I can't imagine why I would care to memorize these, when "==" suffices for all of them. ("is" is valuable for comparing mutable objects, of course, since "a is b" tells me whether changes I make to `b` will be seen in `a`. But for immutable objects, I have yet to see a reason for ever using 'is'.) – Don Hatch Apr 13 '23 at 22:52
  • @DonHatch. `ints` should not be compared by `is` because that's an implementation detail, which BTW, you can bypass even in CPython. `True` and `False` absolutely should be compared by `is`, for the same reason as `None`: they are explicitly designed to be singletons by the language. That is not an implementation detail. That being said, you are free to use `==`. It's a matter of speed (which does not matter if you're using python), and convention, which does if you want others to read your code. – Mad Physicist Apr 13 '23 at 23:50