I think wasting of indentation levels for a single logical block should be avoided if possible to make the code more legible, otherwise one hits the suggested line length limit too fast - suppose this is now inside a method, you already lose at least 8 char ...
Hence generators, which allow the nested loops to be readily factored out into a named operation.
def iter_interesting_triples(seq1, seq2, seq3): for x in seq1: if p1(x): for y in seq2: if p2(x, y): for z in seq3: if p3(x, y, z): yield x, y, z
for x, y, z in iter_interesting_triples(seq1, seq2, seq3): f(x, y, z)
This is an elegant solution, but I think it makes the code less clear if one has to loop up the definition of the generator. I any case, irrespective of limits or being dispensable, I think it would be more consistent for the language to allow the same syntax for "for" loops as is allowed in comprehensions.