== compares VALUES (equality); is compares IDENTITY (whether two names point to the exact same object in memory). Using is for value comparison is a subtle, common bug.
a == b asks 'are these equal?'; a is b asks 'are these the same object?'. They coincidentally agree for small integers (-5..256) and interned strings due to caching, which misleads people into using is for values. The correct uses of is are comparing to singletons: x is None, x is True/False (rarely), and type checks via isinstance. For everything else (numbers, strings, lists), use ==. A classic trap: if status is 200 may work in a REPL (cached int) but fail for computed values; always write if status == 200.
Checking an optional parameter: if config is None: config = {} correctly tests the singleton None, whereas if config == None is discouraged (and is-comparison of computed values like ids must use ==).
if response_code is 200 passes in testing but fails in production for the same value. Explain.