
Terry Reedy schrieb am So, 11. Dez 2011, um 01:02:30 -0500:
Expecting contextlib to have such a specialized context manager that does exactly what you want is perhaps too much.
I don't think this is a very specialised need. It would overcome a fundamental limitation of context managers compared to some clean-up constructs in other languages. An example is Go's 'defer', which is Go's replacement for try/finally blocks and context managers. It defers a function call to the time the current function returns, and guarantees the deferred call will be executed no matter how control leaves the current function -- just like a 'finally' clause.
The advantage of 'defer' over 'with' and try/finally blocks is that it is not a compound statement, so you can "conditionally add a 'finally' clause". Returning to the example from the original post, let's see how it would look in Go:
func Fn(a_file *os.File) (err os.Error) { if a_file == nil { a_file, err = os.Open(a_default_location, os.O_RDONLY, 0) if err != nil { return } defer a_file.Close() } // do stuff return }
to achieve exactly what is desired. The line 'defer a_file.Close()' is only executed when we actually need to close the file.
Note that the disadvantage of 'defer' is also that it is not a compound statement -- it is bound to the block defined by the current function and in this regard less flexible than 'with' blocks.
We could add our own version of 'defer' to Python by offering a context manager 'Deferrer' with a 'push()' method to push a clean-up call-back on the Deferrer's stack. This design would offer the combined advantages of both approaches described above. I, for one, do think that this would make a very worthwhile addition to the 'contextlib' module.
We discussed such a context manager less than two weeks ago on this list
http://mail.python.org/pipermail/python-ideas/2011-October/012418.html
and Jan Kaliszewski even provided an implementation:
http://mail.python.org/pipermail/python-ideas/2011-October/012463.html
What do you think?
Cheers, Sven