Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Python Dictionary

  1. Home
  2. Python Dictionary
  3. is Operator (Identity Check)

is Operator (Identity Check)

Python's is operator checks object identity. While == compares whether values are equal, is checks whether two references point to the same object in memory. PEP 8 convention is to use is (not ==) when comparing against None, True, or False. On the other hand, integer and string interning (internal caching) can cause is to return True by coincidence, so using is for value comparison is dangerous.

Syntax

# Check whether two references point to the same object (returns True or False).
object_a is object_b

# Check whether two references point to different objects (returns True or False).
object_a is not object_b

# Recommended pattern for None checks
if variable is None:
    # code when variable is None

if variable is not None:
    # code when variable is not None

Operators

SyntaxNotes
a is bReturns True if a and b are the same object (same memory address).
a is not bReturns True if a and b are different objects.
a == bReturns True if the values of a and b are equal. Can be True even if they are not the same object.
variable is NoneChecks whether a variable is None. PEP 8 recommends using is for None comparisons.
variable is not NoneChecks whether a variable is not None. PEP 8 recommends using is not for None comparisons.

Sample Code

Comparing is and ==. This sample uses characters from the Yakuza (Like a Dragon) series.

is_vs_equal.py
# Define character data as dictionaries.
kiryu = {"name": "Kiryu Kazuma", "title": "Dragon"}
majima = {"name": "Majima Goro", "title": "Mad Dog"}

# Create a separate object with the same content.
kiryu_copy = {"name": "Kiryu Kazuma", "title": "Dragon"}

# == compares values.
print(kiryu == kiryu_copy)    # True (same content)
print(kiryu == majima)        # False (different content)

# is checks identity (same memory address).
print(kiryu is kiryu_copy)    # False (two separately created objects)
print(kiryu is majima)        # False

# Assigning the same object to another variable makes is return True.
kiryu_ref = kiryu
print(kiryu_ref is kiryu)     # True (points to the same object)
print(kiryu_ref == kiryu)     # True

# id() shows the memory address.
print(id(kiryu))              # e.g. 140234567890
print(id(kiryu_ref))          # same address
print(id(kiryu_copy))         # different address
python3 is_vs_equal.py
True
False
False
False
True
True
140234567890128
140234567890128
140234567891264

Using is for None checks. Since None is a singleton (only one exists in Python), comparing with is is reliable.

none_check.py
# Manage character data in a dictionary. None means not set.
character_data = {
    "kiryu":   {"name": "Kiryu Kazuma", "partner": None},
    "majima":  {"name": "Majima Goro", "partner": "Nishida"},
    "saejima": {"name": "Saejima Taiga", "partner": None},
}

# Use is None to check for unset values (recommended).
for key, data in character_data.items():
    if data["partner"] is None:
        print(data["name"] + ": no partner set")
    else:
        print(data["name"] + " partner: " + data["partner"])

print()

# == None also works, but is None is preferred.
# Reason: objects with __eq__ overridden may behave unexpectedly with == None.
value = None
print(value is None)    # True (recommended)
print(value == None)    # True (works but not preferred)

# Use is not None to handle the case where a value exists.
def get_title(name):
    titles = {"Kiryu Kazuma": "Dragon", "Majima Goro": "Mad Dog"}
    return titles.get(name)   # Returns None if not found.

title = get_title("Kiryu Kazuma")
if title is not None:
    print("Title: " + title)
else:
    print("No title")
python3 none_check.py
Kiryu Kazuma: no partner set
Majima Goro partner: Nishida
Saejima Taiga: no partner set

True
True
Title: Dragon

The pitfall of integer and string interning with is. Small integers and short strings may cause is to return True by coincidence, but this cannot be relied upon. When running as a script, compile-time constant folding may cause is to return True even for integers above 256 or strings containing special characters. In interactive mode (REPL), False is the more common result, and the outcome varies depending on how the code is executed.

interning_pitfall.py
# Integer interning: Python caches integers from -5 to 256.
# Within this range, integers with the same value are the same object.
a = 100
b = 100
print(a is b)    # True (cached in the -5 to 256 range)
print(a == b)    # True

# Above 256, separate objects may be created (varies by environment).
# When run as a script, CPython performs constant folding and merges
# identical literals within the same code object, resulting in True.
x = 1000
y = 1000
print(x is y)    # True (constant folding at compile time merges the literals)
print(x == y)    # True (values are equal)

# String interning: simple identifier-like strings are likely to be interned.
name1 = "kiryu"
name2 = "kiryu"
print(name1 is name2)    # True (often interned)

# Strings with spaces can also be merged by constant folding when run as a script.
title1 = "Kiryu Kazuma"
title2 = "Kiryu Kazuma"
print(title1 is title2)  # True (constant folding at compile time merges the literals)
print(title1 == title2)  # True (value comparison is reliable)

# Summary: use == for string and integer value comparisons.
# Results with is can vary across environments and Python versions.
python3 interning_pitfall.py
True
True
True
True
True
True
True

Why isinstance() is used for type checking. is and type() == do not account for inheritance.

type_check.py
# Define a base class and a derived class.
class Character:
    def __init__(self, name):
        self.name = name

class MainCharacter(Character):
    def __init__(self, name, title):
        super().__init__(name)
        self.title = title

# Create instances.
kiryu = MainCharacter("Kiryu Kazuma", "Dragon")
npc = Character("Passerby A")

# isinstance() includes subclasses in the check (recommended).
print(isinstance(kiryu, MainCharacter))   # True
print(isinstance(kiryu, Character))       # True (MainCharacter is a subclass of Character)
print(isinstance(npc, MainCharacter))     # False

# type() == does not consider subclasses.
print(type(kiryu) == MainCharacter)       # True
print(type(kiryu) == Character)           # False (subclass not included)

# type() is also does not consider inheritance.
print(type(kiryu) is Character)           # False

# Use isinstance() for code that leverages polymorphism.
characters = [kiryu, npc, MainCharacter("Majima Goro", "Mad Dog")]
for chara in characters:
    if isinstance(chara, MainCharacter):
        print(chara.name + " (" + chara.title + ") is a main character")
    else:
        print(chara.name + " is a generic character")
python3 type_check.py
True
True
False
True
False
False
Kiryu Kazuma (Dragon) is a main character
Passerby A is a generic character
Majima Goro (Mad Dog) is a main character

Common Mistakes

Common Mistake 1: Using is for value comparison and depending on interning

Small integers (-5 to 256) and short identifier-like strings are cached (interned) by Python. Within this range, is happens to return True, but outside the range or on a different execution environment the result can change. Writing literals directly in a script can cause constant folding to return True, so the sample below uses variable-based computation to reliably produce separate objects. Use == for value comparisons.

ng_intern_trap.py
a = 256
b = 256
print(a is b)    # True (within the interned range, coincidentally True)

base = 250
x = base + 7   # 257
y = base + 7   # 257 (separate computation, separate object)
print(x is y)    # False (separate objects)

name1 = "kiryu"
name2 = "kiryu"
print(name1 is name2)    # True (likely to be interned)

prefix = "Kiryu"
title1 = prefix + " Kazuma"
title2 = prefix + " Kazuma"   # separate concatenation, separate object
print(title1 is title2)  # False (separate objects)
python3 ng_intern_trap.py
True
False
True
False
ok_equal_compare.py
# Use == for value comparisons.
a = 257
b = 257
print(a == b)    # True (reliable regardless of environment)

name1 = "Kiryu Kazuma"
name2 = "Kiryu Kazuma"
print(name1 == name2)    # True (value equality comparison)
python3 ok_equal_compare.py
True
True

Common Mistake 2: Using == None where is None should be used

Using == None on an object from a custom class with __eq__ overridden may produce unexpected results. Using is None checks identity without depending on the __eq__ implementation, making it reliable.

ng_eq_none.py
# Example of a class with __eq__ overridden
class Dominator:
    def __eq__(self, other):
        # Wrong: __eq__ always returns True (extreme example)
        return True

d = Dominator()
print(d == None)   # True (__eq__ override causes unexpected behavior)
print(d is None)   # False (identity check is accurate)
python3 ng_eq_none.py
True
False
ok_is_none.py
character_data = {
    "kiryu":   {"name": "Kiryu Kazuma", "partner": None},
    "majima":  {"name": "Majima Goro", "partner": "Nishida"},
}

for key, data in character_data.items():
    # is None is not affected by __eq__.
    if data["partner"] is None:
        print(data["name"] + ": no partner set")
    else:
        print(data["name"] + ": " + data["partner"])
python3 ok_is_none.py
Kiryu Kazuma: no partner set
Majima Goro: Nishida

Common Mistake 3: Confusing is not with not is, causing SyntaxError

is not None is a two-word operator. Writing not is None causes a SyntaxError. Similarly, not in is a two-word operator; in not is incorrect.

ng_not_is.py
value = "Kiryu Kazuma"
# This works syntactically but is not recommended by PEP 8.
if not value is None:
    print("value exists")
ok_is_not.py
value = "Kiryu Kazuma"
# Use is not (two-word operator).
if value is not None:
    print("value exists:", value)

result = None
if result is None:
    print("result is not set")
python3 ok_is_not.py
value exists: Kiryu Kazuma
result is not set

Notes

The distinction between is and == matters. is checks object identity (same memory address), while == checks value equality. Using is for value comparison is an error; even if interning causes it to return True for integers and strings, that is an implementation detail and is not guaranteed to hold in the future.

PEP 8 convention is to use is (and is not) when comparing against None. None is a singleton (only one exists in Python), so comparing with is None is reliable and clearly expresses intent. While == None works in most cases, it may behave unexpectedly when compared with objects whose __eq__ is overridden.

For type checking, isinstance() is common. Using type(obj) is SomeClass or type(obj) == SomeClass cannot account for subclasses, so care is needed. isinstance() includes subclasses in its check, making it suitable for code that leverages polymorphism. See isinstance() / issubclass() / type() for details. For the distinction from the in operator (containment check), see in operator.

If you find any errors or copyright issues, please .