Dive as deep as possible, then backtrack.
def dfs(graph, node, visited=None):
if visited is None: visited = set()
visited.add(node) # Enter / Visit
for nb in graph[node]:
if nb not in visited: # Traverse
dfs(graph, nb, visited) # Backtrack
Dynamically typed and interpreted — every comparison and swap is dispatched by the interpreter at run time, so tight loops run roughly 10–100× slower than compiled C/C++. Unbeatable for learning the idea with the least code; not what you reach for when the inner loop is the bottleneck.