isIntermediate Examples

Identity operator; tests whether two variables reference the same object

is vs == in practice

Understanding when to use identity vs equality.

python
# Singletons: use 'is'
print(True is True)
print(None is None)

# Small integer caching (-5 to 256)
a = 256
b = 256
print(f"256 is 256: {a is b}")  # True (cached)

a = 257
b = 257
print(f"257 is 257: {a is b}")  # May be False!

# String interning
s1 = "hello"
s2 = "hello"
print(f'"hello" is "hello": {s1 is s2}')  # Usually True (interned)

# == can be overridden, is cannot
class AlwaysEqual:
    def __eq__(self, other):
        return True

obj = AlwaysEqual()
print(f"obj == 42: {obj == 42}")
print(f"obj is 42: {obj is 42}")

'is' is a pointer comparison that cannot be overridden. '==' calls __eq__ which can return anything. Use 'is' for singletons, '==' for value comparison.

is not: the complement

Using 'is not' for negative identity checks.

python
# is not (preferred over 'not ... is')
result = "hello"
print(result is not None)

# Sentinel pattern
_MISSING = object()  # unique sentinel

def get_config(key, default=_MISSING):
    config = {"debug": True, "verbose": False}
    value = config.get(key, _MISSING)
    if value is _MISSING:
        if default is _MISSING:
            raise KeyError(f"No config for {key!r}")
        return default
    return value

print(get_config("debug"))
print(get_config("missing", "fallback"))
try:
    get_config("missing")
except KeyError as e:
    print(f"Error: {e}")
Expected Output
True
True
fallback
Error: "No config for 'missing'"

The sentinel pattern uses a unique object() as a default value. Since each object() has unique identity, 'is' can distinguish 'not provided' from any possible user value.

Want to try these examples interactively?

Open Intermediate Playground