Identity operators is
and is not
check if the same object is on both sides, i.e. a is b
returns
True
if id(a) == id(b)
.
Integers, bytes, floats, strings, frozensets and tuples should not be compared with identity operators because the result may not be as expected.
If you need to compare these types you should use instead equality operators ==
or !=
.
The CPython interpreter caches certain builtin values for integers, bytes, floats, strings, frozensets and tuples. For example, the literal
1
will create the same object as int("1")
, which means that 1 is int("1")
is True. However this works only by
chance as other integer values are not cached, for example int("1000") is 1000
will always be False
. This behavior is not
part of Python language specification and could vary between interpreters. CPython 3.8 even warns about comparing literals using identity operators.
The only case where using the "is" operator with a cached type is ok is with "interned" strings. Note however that interned strings don’t
necessarily have the same identity as string literals.
This rule raises an issue when at least one operand of an identity operator:
- is of type
int
, bytes
, float
, frozenset
or tuple
.
- or it is a string literal.
Noncompliant Code Example
def literal_comparison(param):
param is 2000 # Noncompliant
literal_comparison(2000) # will return True
literal_comparison(int("2000")) # will return False
() is tuple() # Noncompliant. Always True
(1,) is tuple([1]) # Noncompliant. Always False
from sys import intern
with open("test.txt") as f: # test.txt contains "blabla\n"
text = f.read()
intern(text) is "blabla\n" # Noncompliant. Always False
Compliant Solution
def literal_comparison(param):
param == 2000
literal_comparison(2000) # will return True
literal_comparison(int("2000")) # will return True
() == tuple() # Always True
(1,) == tuple([1]) # Always True
from sys import intern
with open("tmp/test.txt") as f: # test.txt contains "blabla\n"
text = f.read()
intern(text) is intern("blabla\n") # Always True
See