VMware ESXi and vSphere Cluster Management
Python Identity Operators: is and is not
Learn how Python's is and is not operators compare object identity, how identity differs from equality, and when to use None, type, and isinstance checks.
What object identity means
In Python, every object has an identity during its lifetime. Object identity answers one specific question: do two references point to the exact same object?
A reference is a name or expression that points to an object. If two variables refer to one shared object, they have the same object identity. Identity is different from an object's value, contents, class, or type. Two lists can contain the same values while still being two separate objects.
Python's identity operators are is and is not. They compare references to objects rather than comparing the objects' ordinary data values.
The is operator
The expression left is right produces the Boolean value True only when both operands refer to the same exact object. Otherwise, it produces False.
When one assignment gives a second name to an existing object, the two names are aliases. An alias is a second variable name that refers to an object already referenced by another name.
first = [1, 2]
second = first
print(first is second) # True
print(first == second) # True
second = first does not create a new list. Both names refer to the same list, so identity and equality are both true. This also means that a mutation through either name affects the same object:
second.append(3)
print(first) # [1, 2, 3]
The result of is is always a Boolean result: True or False.
The is not operator
The expression left is not right produces True when the operands refer to different objects. It produces False when they refer to the same object. Therefore, is not is the logical opposite of is.
first = [1, 2]
third = [1, 2]
print(first is third) # False
print(first is not third) # True
Although first and third contain matching values, the two list expressions create separate list objects. They are not identical.
Identity versus equality
Equality is a comparison of values or contents, generally performed with ==. The expression a == b asks whether the objects should be considered equal according to their equality behavior. The expression a is b asks whether the two references identify one object.
first = [1, 2]
second = first
third = [1, 2]
print(first is second) # True
print(first == second) # True
print(first is third) # False
print(first == third) # True
first and second are aliases, so they are identical and equal. first and third are separate lists, so they are not identical, but their contents are equal.
Identical objects will normally compare equal because an object is equal to itself. However, equal objects are not necessarily identical. This distinction is especially important for lists, dictionaries, strings, numbers, and other data values.
The most important use: checking for None
None is Python's singleton object for representing the absence of a value. A singleton is an object intended to have one shared instance. Because the intended question is whether a reference points to that particular object, use identity operators:
result = None
if result is None:
print('No result available')
To check that a value is present, use is not None:
result = get_result()
if result is not None:
print(result)
value == None is less appropriate. Equality can be customized by a class, so it may not mean exactly “is this the singleton None object?” The identity check is precise and communicates the intended test clearly.
Identity and exact type checks
The built-in type() function returns a type object describing an object's exact type. Since type objects are objects themselves, identity can compare the result of type() with a type such as int.
x = 5
print(type(x) is int) # True
print(type(x) is not float) # True
y = 3.23
print(type(y) is float) # True
print(type(y) is int) # False
Read type(x) is int as follows:
type(x)returns the type object for the value5.intrefers to the built-ininttype object.iscompares those two type objects by identity.
Thus, this expression does not compare the integer value 5 directly with a type. It compares the type object returned by type(x) with the int type object.
type(value) is not float tests that the value's exact type is not the built-in float type. It is an exact-type test, not a general test for whether a value can be treated as a particular kind of object.
Exact type versus subclass-aware checks
A class can have subclasses. A subclass is a class that inherits behavior from another class. The expression type(value) is BaseClass is true only when the exact type is BaseClass; it rejects instances of subclasses.
Use isinstance(value, ExpectedType) when instances of the expected type or its subclasses should be accepted:
class SpecialInt(int):
pass
value = SpecialInt(5)
print(type(value) is int) # False
print(isinstance(value, int)) # True
The exact-type check and the inheritance-aware check have different purposes:
- Use
type(value) is SomeTypewhen only the exact built-in or class type is valid. - Use
isinstance(value, SomeType)when a subclass should count as an acceptable instance.
Why is should not compare ordinary values
Do not use is to compare ordinary numbers, strings, tuples, lists, or other data values. Use == for values and contents, and != for unequal values.
name_from_input = ''.join(['Py', 'thon'])
name_expected = 'Python'
print(name_from_input == name_expected) # True
print(name_from_input is name_expected) # Do not rely on this
Python implementations may use interning and caching, runtime optimizations that cause some immutable values to share an object identity. For example, a particular short string or small integer may happen to be stored once and reused. Another value may be created as a separate object. These implementation details can make an identity comparison appear to work in one example but fail in another.
Shared identity is not a guarantee that two data values are equal, and equal values are not required to share identity. The correct rule is simple:
- Use
==or!=when the question concerns a value or its contents. - Use
isoris notwhen the question concerns the exact object being referenced.
Readable identity expressions
Identity operators work naturally in conditional statements:
if response is None:
print('The operation returned no response')
elif response is not None:
print('The operation returned a response')
Prefer the dedicated expression a is not b rather than writing not a is b. Both express negation, but is not is clearer and directly names the intended operator.
# Clear
if cached_value is not None:
use(cached_value)
# Less readable
if not cached_value is None:
use(cached_value)
Clear variable names and direct Boolean conditions make identity checks easier to understand. A condition should reveal whether you are checking for a shared object, a missing value, or an exact type.
Common mistakes and fixes
Using identity for data comparison
Mistake: Comparing two strings, numbers, or lists with is.
Symptom: The comparison appears to work for some values but produces an unexpected result for others.
Cause: Object sharing, interning, and caching affect identity; they do not define value equality.
Fix: Use == or != for ordinary values.
Using equality to check for None
Mistake: Writing value == None.
Cause: Equality behavior can be customized by an object's class.
Fix: Write value is None or value is not None.
Expecting an exact type check to accept subclasses
Mistake: Assuming type(value) is BaseClass accepts an object created from a subclass.
Cause: The expression requires an exact type match.
Fix: Use isinstance(value, BaseClass) when subclasses are valid.
Misreading type(value) is int
Mistake: Thinking that is directly compares a value with a type.
Fix: Remember that type(value) returns a type object. The identity comparison is between that returned type object and the int type object.
Quick decision guide
- Are you asking whether two names refer to the exact same object? Use
a is b. - Are you asking whether two references point to different objects? Use
a is not b. - Are you checking for Python's missing-value singleton? Use
value is Noneorvalue is not None. - Are you requiring an exact type? Use
type(value) is RequiredType. - Should subclasses be accepted? Use
isinstance(value, RequiredType). - Are you comparing numbers, text, collections, or other ordinary data? Use
==or!=.
For more practice with this topic, return to Python identity operators and test each expression in a Python interactive shell.