Problem with context managers is that they add up indentation really, really fast. I guess TFA is at least a partial remedy to this though!
C#8 then allowed using-statements that do not require blocks, which then are disposed when leaving the current block.
Pre C#8, you had to have a block, similar to how with-statement requires a block aka indentation
using (var res = OpenSomeResource()) {
res.doSomething();
// res.Dispose() implicitly called
}
Now you can have this (which is a bit like a go-style Defer but for blocks) using var res = OpenSomeResource();
res.doSomething();
// res.Dispose() implicitly called at end of current block
Of course, you have to take the potentially longer lifetime into account. This way looks a lot like C++s RAII with constructors and destructors (except the destructor here is the IDisposible.Dispose implementation). def do_thing():
with open('foo', 'r') as f
with a_lock
f.read()
frobnicate()
I guess the issue is that there is less of a clear idea of scope in Python, what does the above construct do at a module level? What does it do inside another with block? A lot of special rules that don't conveniently fit into something else unlike what I suppose C# has.This is actually vaguely reminiscent of auto release pools in Cocoa.
def do_thing():
with a_lock
check_f_cache_while_locked() # like this
with open('foo', 'r') as f
populate_cache(f) with open("foo.txt") as foo_file, open("bar.txt") as bar_file, open("baz.txt", "w") as baz_file:
baz_file.write(foo_file.read() + bar_file.read()) with (open("foo.txt") as foo_file,
open("bar.txt") as bar_file,
open("baz.txt", "w") as baz_file):
baz_file.write(foo_file.read() + bar_file.read())