getting with statement to deal with various exceptions

mk mrkafk at gmail.com
Sun Jul 20 08:42:09 EDT 2008


Hello,

I'm trying to learn how with statement can be used to avoid writing:

prepare()
try:
	something_that_can_raise_SomeException()
except SomeException, err:
	deal_with_SomeException
finally:
	tear_it_down()

Verbose, not very readable. OK, "with" to the rescue?

Let's take a textbook example from PEP:

with open('/etc/passwd', 'r') as f:
     BLOCK

Well, great, it's neat that "with" closes the file after BLOCK has 
finished execution, but what if the file isn't there and attempt to open 
it raises IOException? I'd like to be able to catch it precisely to 
avoid writing verbose try: .. except: .. finally: .. blocks which as I 
understand has been much of the rationale behind creating "with" 
statement in the first place.

"with" statement only allows easy dealing with prepare() and 
tear_it_down(). When I try to get it to deal with exceptions that might 
happen, it becomes more complicated:

class FileContextManager:
	def __enter__(self, filename, mode):
		f = open(filename, mode)
		return f
	def __exit__(self, etype, evalue, etraceback):
		print "etype", etype, "evalue", evalue, "etraceback", etraceback

		
 >>> with FileContextManager("somefile", "r") as f:
	a = f.readlines()

	

Traceback (most recent call last):
   File "<pyshell#36>", line 1, in <module>
     with FileContextManager("somefile", "r") as f:
TypeError: this constructor takes no arguments


Bummer.

Plus, no documentation I've read (on effbot, in PEP 343, etc) says how 
to deal with the exception happening in __enter__ method of context 
manager, which is precisely what I'd like to do.

This is only natural, isn't it? When e.g. reading the file, preparation 
phase is typically checking if it can be opened in the first place. So 
it falls into __enter__ method of context manager.

"with" limited only to successful execution of a_statement from "with 
a_statement" seems like limited benefit to me.

I'd like to be able to write smth like

class FileContextManager:
	def __enter__(self, filename, mode):
		f = open(filename, mode)
		return f
	def __except__(IOError, err):
		do_this
		print err
	def __except__(RuntimeError, err):
		do_that
		print "something bad happened", err
	def __exit__(self, etype, evalue, etraceback):
		print "etype", etype, "evalue", evalue, "etraceback", etraceback

__exit__ deals with exceptions happening in the BLOCK below "with" 
statement, not with exceptions raised in "a_statement", when executing

with a_statement as var:
	BLOCK

In the above way "with" would give me the benefit of more terse, but 
still understandable and efficient code.

Well, I can always do this:

try:
	with open("somefile.txt") as txtfile:
		for line in txtfile:
			print line
except IOError:
	print "No such file."

	
No such file.


But that's just ugly, nested too many times (flat is better than nested, 
right?) and not all that more readable.






More information about the Python-list mailing list