classification
Title: Support Multiple finally clauses.
Type: Stage:
Components: Versions:
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: georg.brandl, jcea, josh.r, kevincox, rhettinger
Priority: normal Keywords:

Created on 2014-03-25 22:44 by kevincox, last changed 2014-03-26 08:05 by rhettinger. This issue is now closed.

Messages (4)
msg214861 - (view) Author: Kevin Cox (kevincox) Date: 2014-03-25 22:44
I think it would be useful to support multiple finally clauses.  The idea would be that each clause would be run, even if prior clauses throw exceptions.

The idea came when hunting a bug in the Mozilla test suite.  The code looked like as follows.

try:
	resource1 = allocateresource1()
	resource2 = allocateresource2()
	
	dostuffthatmightthrowexception()
finally:
	if resource1:
		resource1.close()
	if resource2:
		resource2.close()

The problem is that if resource1,close() throws an exception resource2 is not closed.

The alternative looks like this.

try:
	resource1 = allocateresource1()
	try:
		resource2 = allocateresource2()
		
		dostuffthatmightthrowexception()
	finally:
		if resource2:
			resource2.close()
finally:
	if resource2:
		resource2.close()

Or it could look like this.

try:
	resource1 = allocateresource1()
	resource2 = allocateresource2()
	
	dostuffthatmightthrowexception()
finally:
	try:
		if resource1:
			resource1.close()
	finally:
		if resource2:
			resource2.close()

Both of which exhibit indentation explosion when there are a number of resources that need to be cleaned up.

If multiple finally clauses were allowed the code would be much more readable and would look as follows.

try:
	resource1 = allocateresource1()
	resource2 = allocateresource2()
	
	dostuffthatmightthrowexception()
finally:
	if resource1:
		resource1.close()
finally:
	if resource2:
		resource2.close()
msg214862 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2014-03-25 22:54
For resource management, it would be more idiomatic to use context managers, either with multiple CMs in one with-statement or, dynamically, with contextlib.ExitStack.

For test suites using unittest, there is also the addCleanup functionality of the TestCase.  (And if another test framework is used, it might have something similar, or maybe should grow it.)

Anyway, such changes are not decided upon in the tracker. If you think this should go forward please discuss it on the python-ideas list. For it to go forward a PEP will likely need to be written.
msg214879 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2014-03-26 03:58
And for this particular case, even if the resource allocators don't support the context manager protocol, contextlib.closing can do the job:

    from contextlib import closing

    with closing(allocateresource1()) as resource1, closing(allocateresource2()) as resource2:
	dostuffthatmightthrowexception()

If it's not a simple as calling close, you can write your own simple manager wrapper that calls some other cleanup function use @contextlib.contextmanager.
msg214881 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-03-26 08:05
> If you think this should go forward please discuss it 
> on the python-ideas list. For it to go forward a PEP 
> will likely need to be written.

I concur with this assessment.

Marking this as closed.
History
Date User Action Args
2014-03-26 08:05:15rhettingersetstatus: open -> closed

nosy: + rhettinger
messages: + msg214881

resolution: rejected
2014-03-26 03:58:27josh.rsetnosy: + josh.r
messages: + msg214879
2014-03-25 22:59:46jceasetnosy: + jcea
2014-03-25 22:54:47georg.brandlsetnosy: + georg.brandl
messages: + msg214862
2014-03-25 22:44:17kevincoxcreate