Python iterators, and generators in particular, exist exactly to allow the nice refactoring of otherwise-complicated loops. Of course, it's hard to get an abstraction out from a simple example, but assuming the 3
needs to be a parameter (maybe the whole range(3)
should be?), and the two functions you're calling need some parameters that are loop variables, you could refactor the code:
for y in range(3):
for x in range(3):
do_something(x, y)
for y1 in range(3):
for x1 in range(3):
do_something_else(x, y, x1, y1)
into, e.g.:
def nestloop(n, *funcs):
head = funcs[0]
tail = funcs[1:]
for y in range(n):
for x in range(n):
yield head, x, y
if tail:
for subtup in nestloop(n, *tail):
yield subtup[:1] + (x, y) + subtup[1:]
for funcandargs in nestloop(3, do_something, do_something_else):
funcandargs[0](*funcandargs[1:])
The exact kind of refactoring will no doubt need to be tweaked for your exact purposes, but the general point that iterators (and usually in fact just simple generators) afford very nice refactorings of loops remains -- all the looping logic goes inside the generator, and the application-level code is left with simple for
loops and actual application-relevant processing of the items yielded in the for loops.