Gotchas & PitfallsLesson 1 of 2
None, is vs ==
JS has two "empty" values: null and undefined. Python has only one: None. No undefined means that reading a variable that was never assigned is always an error (NameError), not a silent undefined. This is actually a feature; bugs surface immediately instead of propagating.
The is operator checks identity (whether two names point to the same object in memory), while '==' checks equality (whether two objects have the same value). Here is the mapping that trips JS developers up: for objects and arrays, JS's === already compares references, so [1, 2] === [1, 2] is false in JS. Python's is is that reference check. Python's '==' goes further and compares contents, so [1, 2] == [1, 2] is True. There is no built-in deep-equality operator in JS; in Python, == is it.
Python's == also never converts strings to numbers ("5" == 5 is False), so you never need a separate strict operator. Numbers are still compared by value across types, though: 1 == 1.0 is True, and because bool is a subclass of int, True == 1 is True too.
The rule is simple: use is for None (and for sentinel objects you create yourself). Use '==' for everything else. Writing 'if x == None' works but is considered bad style; PEP 8 explicitly says use 'is None'. And do not write 'if flag is True' or 'if flag == True'; just write 'if flag:'.
Quick reference
| JavaScript | Python | Note |
|---|---|---|
| null | None | Capital N |
| undefined | Does not exist | NameError instead |
| "5" == 5 (true) | "5" == 5 (False) | No string/number coercion |
| a === b (objects) | a is b | Same object in memory |
| deep-equal helper | a == b | Compares contents of lists, dicts... |
| x ?? defaultVal | x if x is not None else d | No ?? operator |
| obj?.a?.b | d.get("a", {}).get("b") | No optional chaining |
Side by side
// JavaScript
let x = null;
let y = undefined;
typeof null; // "object" (JS bug)
null == undefined; // true (loose)
null === undefined; // false (strict)
[1, 2] === [1, 2]; // false (different arrays)
if (x === null) { }
const city = user?.address?.city;
const name = input ?? "default";# Python - only None
x = None
type(None) # <class 'NoneType'>
# is vs == (CRITICAL)
a = [1, 2, 3]
b = [1, 2, 3]
a == b # True (same contents)
a is b # False (different objects!)
# ALWAYS use 'is' for None
if x is None: # correct
pass
if x is not None: # correct
pass
# Default values
name = inp if inp is not None else "default"
name = inp or "default" # catches ALL falsy!
# Nested lookups without ?.
city = user.get("address", {}).get("city")Exercise
Real Python, running in your browserFix all the bugs in this code (there are 4 issues):
x = undefined
if x == None:
print("x is empty")
a = [1, 2]
b = [1, 2]
if a is b:
print("lists are equal")
result = x ?? "default"x is empty lists are equal
Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment