Let's solve the following problem: write a function that returns the index of e in the list L if e is in L, and None otherwise:
def find_i(L, e):
for i in range(len(L)):
if L[i] == e:
return i
return None
Suppose we are interested in how fast this code runs. What sort of answer can we expect?
Ideally, we'd know the answer in seconds -- but of course, that answer would depend on the kind of computer that we are using.
Alternatively, maybe we'd like the answer to be in terms of the number of elementary operations that Python performs -- how many comparisons (i.e., uses of ==) we make, how many times we access elements of L, and so on. This is easier, but still not that easy -- precisely specifying what an elementary operation is is not that trivial, and modern CPUs try to optimize the runtime in such a way that it's hard to predict what an elemntary operation is.
Still, if we could say that the function runs $k*1000$ elementary operations when L[k] == e, that would be useful: roughly speaking, one computer might take, say, 1 nanosecond per elementary operation, and another would take 2 nanoseconds per elementary operation. So knowing how many elementary operations we take to run an algorithm could be useful.
Because of the difficulties of counting elementary operations, we usually pick an appropriate loop, and count how many iterations of that loop are run. We pick the loop in such a way that the number of iterations of the loop is proportional to the total number of elementary operations performed.
That way, if, say, the loop runs $k$ times, then we know that the amount of time take will be proportional to $k$. This is similar to what happenned with counting elementary operations.
So what's the answer here?
find_i(L, e) runs for k iterations if L[k] == e, and for len(L) iterations otherwise.