For simple cases, yes, the two-level with
and for
is idiomatic.
For cases where the indentation becomes a problem, here as anywhere else in Python, the idiomatic solution is to find something to factor out into a function.
You can write wrappers to help this. For example, here's a simple way to solve some of the problems you use with
for (e.g., even in the best case, the file sticks around after you finish the loop, until the end of the scope—which could be days later, or never, if the scope is a main event loop or a generator or something…):
def with_iter(iterable):
with iterable:
yield from iterable
for line in with_iter(open("filename")):
# do something
for line in with_iter(open("other_filename")):
# do something else
Of course it doesn't solve everything. (See this ActiveState recipe for more details.)
If you know that it does what you want, great. If you don't understand the differences… stick to what's idiomatic; it's idiomatic for a reason.
So, how do you refactor the code? The simplest way is often to turn the loop body into a function, so you can just use map
or a comprehension:
def do_with_line(line):
return line
with open("filename") as f:
process = [do_with_line(line) for line in f]
But if the problem is that the code above or underneath the for
is too deep, you'll have to refactor at a different level.