/compare/python/is-vs-double-equals
Python is vs ==: identity vs equality
- tool
- Python
- compares
- is vs ==
a == b asks whether two objects have the same value (it calls __eq__); a is b asks whether they are the same object in memory (id(a) == id(b)). Use == for comparing data, and is only for singletons: x is None, x is not None, and sentinel objects.
The difference in practice
cat > cmp.py <<'EOF'
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print("a == b:", a == b) # same value
print("a is b:", a is b) # different objects
print("a is c:", a is c) # c is another name for a
x = None
print("x is None:", x is None)
print(int("256") is int("256"), int("257") is int("257"))
EOF
python cmp.pyOutput
a == b: True a is b: False a is c: True x is None: True True False
The last line shows a CPython implementation detail: integers from -5 to 256 are cached, so two of them are the same object, while larger ones created at runtime usually are not. Code must never rely on that.
When == and is disagree
Because == runs code from the object's class, the two operators can give opposite answers even for None, and floating-point NaN is not equal to itself:
cat > eq.py <<'EOF'
class Always:
def __eq__(self, other):
return True
obj = Always()
print("obj == None:", obj == None)
print("obj is None:", obj is None)
nan = float("nan")
print("nan == nan:", nan == nan, " nan is nan:", nan is nan)
print("nan in [nan]:", nan in [nan])
built = "".join(["err", "codex"])
literal = "errcodex"
print("built == literal:", built == literal, " built is literal:", built is literal)
EOF
python eq.pyOutput
obj == None: True obj is None: False nan == nan: False nan is nan: True nan in [nan]: True built == literal: True built is literal: False
obj == NoneisTruebecauseAlways.__eq__says so, which is exactly why PEP 8 asks foris None.nan == nanisFalseby the IEEE 754 rules, yetnan in [nan]isTrue: container membership tests (in,list.index,list.count) check identity first and only then call==.- A string built at runtime equals the literal but is a different object, so
isfails where==works.
Criterion by criterion
| Criterion | is | == |
|---|---|---|
| Compares | Object identity (same id) | Values, through __eq__ |
| Can be overridden by a class | No | Yes |
| None, True, False | Recommended (PEP 8) | Works, but a class can make it lie |
| Numbers and strings | Wrong: depends on caching and interning | Correct |
| Speed | Slightly faster (no method call) | Calls __eq__ |
Python warns about is with a literal
python -c 'x = 1000; print(x is 1000)'Output
<string>:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? True
Since Python 3.8, is against a literal emits a SyntaxWarning that suggests ==.
Which one to use
Use == (and !=) whenever you care about the data: numbers, strings, lists, dicts, dataclasses, anything a user typed or a file contained. Use is (and is not) only when you need to know that a name refers to one particular object: None, NotImplemented, Ellipsis, enum members, and private sentinel objects such as _missing = object() used as a default argument. A sentinel works with is precisely because nothing else can be identical to it, even an object that compares equal.
A missing is None check is the usual cause of AttributeError: 'NoneType' object has no attribute: test for None before using a result that may be absent.
FAQ
Why does PEP 8 say to write x is None instead of x == None?
None is a singleton, so identity is the exact test. == calls the object's __eq__ method, which a class can override to return True for anything, so x == None can give the wrong answer.
Is x is not None the same as not x is None?
Yes, they give the same result. PEP 8 recommends is not because it reads as one operator and avoids confusion with not applied to x.
Why does 'abc' is 'abc' sometimes print True?
CPython may reuse one object for identical string constants (interning), so the identity test happens to succeed. It is an implementation detail; strings built at runtime are usually different objects, so compare text with ==.