The technical definition of indentation is discussed in Reference Manual, 2.1.8.
Main points:
Here is an example from the Python reference model of a correctly (though confusingly) indented piece of Python code:
def perm(l): # Compute the list of all permutations of l if len(l) <= 1: return [l] r = [] for i in range(len(l)): s = l[:i] + l[i+1:] p = perm(s) for x in p: r.append(l[i:i+1] + x) return r
def perm(l): """Compute the list of all permutations of l""" if len(l) <= 1: # Error here! return [l] r = [] for i in range(len(l)): s = l[:i] + l[i+1:] p = perm(s) for x in p: r.append(l[i:i+1] + x) return r
A string at the beginning of a Python function definition is always interpreted as a documentation string and becomes an attribute of the function object. Since it is part of the language it must follow the usual rules of indentation. In particular, it sets the indentation level for succeeding lines, so the error is on the next line, which "unindents" to a column not previously used by any block.
Here is the same piece of code more consistently and sensibly indented. This is better than the indentation above but the difference is matter of style ( Python Styleguide, discusses indentation), not correctness.
def perm(l): # Compute the list of all permutations of l if len(l) <= 1: return [l] r = [] for i in range(len(l)): s = l[:i] + l[i+1:] p = perm(s) for x in p: r.append(l[i:i+1] + x) return r
The following example shows various indentation errors. These will raise exceptions when loaded into Python.
def perm(l): # error: first line indented for i in range(len(l)): # error: not indented s = l[:i] + l[i+1:] p = perm(l[:i] + l[i+1:]) # error: unexpected indent for x in p: r.append(l[i:i+1] + x) return r # error: inconsistent dedent