is — Intermediate 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