Skip to lesson
Python for JS Developers

Gotchas & PitfallsLesson 1 of 2

None, is vs ==

4 min

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

JavaScriptPythonNote
nullNoneCapital N
undefinedDoes not existNameError instead
"5" == 5 (true)"5" == 5 (False)No string/number coercion
a === b (objects)a is bSame object in memory
deep-equal helpera == bCompares contents of lists, dicts...
x ?? defaultValx if x is not None else dNo ?? operator
obj?.a?.bd.get("a", {}).get("b")No optional chaining

Side by side

JavaScript
// 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
# 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 browser

Fix all the bugs in this code (there are 4 issues):

Starter code
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"
Expected output
x is empty
lists are equal

Ctrl + Enter runCtrl + Shift + Enter checkTab indentEsc then Tab to leave the editorCtrl + / comment