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.

Python identity operators

Operator — Meaning — Result is True when — Typical use

is — Compares object identity — Both operands refer to the same object — Checking a singleton such as None, or comparing known aliases

is not — Negated identity comparison — The operands refer to different objects — Checking that a value is not None

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.

Identity comparisons versus equality comparisons

Expression — What it compares — Recommended use — Outcome for separate equal lists

a is b — Whether both references identify the same object — Identity checks — False

a is not b — Whether the references identify different objects — Negative identity checks — True

a == b — Values or contents using equality behavior — Compare ordinary data — True

a != b — Whether values or contents are unequal — Negative value comparisons — False

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.

Choosing a None, type, or instance check

Goal — Recommended expression — Reason

Check for no value — value is None — Checks identity with Python's None singleton

Require one exact type — type(value) is RequiredType — Accepts only that exact type

Accept a type and its subclasses — isinstance(value, RequiredType) — Performs an inheritance-aware check

Compare ordinary values — left == right — Compares values or contents

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:

  1. type(x) returns the type object for the value 5.
  2. int refers to the built-in int type object.
  3. is compares 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 SomeType when 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 is or is not when 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 None or value 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.