Python's "only one way to do it" philosophy isn't good?

Lenard Lindstrom len-l at telus.net
Fri Jun 29 22:42:26 EDT 2007


Douglas Alan wrote:
> Lenard Lindstrom <len-l at telus.net> writes:
> 
>> Douglas Alan wrote:
> 
>>> [I]n Python, you can be 100% sure that your files
>>> will be closed in a timely manner without explicitly closing them, as
>>> long as you are safe in making certain assumptions about how your code
>>> will be used.  Such assumptions are called "preconditions", which are
>>> an understood notion in software engineering and by me when I write
>>> software.
> 
>> So documenting an assumption is more effective than removing the
>> assumption using a with statement?
> 
> Once again I state that I have nothing against "with" statements.  I
> used it all the time ages ago in Lisp.
> 

Sorry if I implied that. I assumed it would be clear I was only 
referring to the specific case of implicitly closing files using 
reference counting.

> But (1) try/finally blocks were not to my liking for this sort of
> thing because they are verbose and I think error-prone for code
> maintenance.  I and many others prefer relying on the refcounter for
> file closing over the try/finally solution.  Consequently, using the
> refcounter for such things is a well-entrenched and succinct idiom.
> "with" statements are a big improvement over try/finally, but for
> things like file closing, it's six of one, half dozen of the other
> compared against just relying on the refcounter.
> 

I agree that try/finally is not a good way to handle resources.

> (2) "with" statements do not work in all situations because often you
> need to have an open file (or what have you) survive the scope in
> which it was opened.  You may need to have multiple objects be able to
> read and/or write to the file.  And yet, the file may not want to be
> kept open for the entire life of the program.  If you have to decide
> when to explicitly close the file, then you end up with the same sort
> of modularity issues as when you have to free memory explicitly.  The
> refcounter handles these sorts of situations with aplomb.
> 

Hmm. I come from a C background so normally don't think of a file object 
as leading a nomadic life. I automatically associate a file with a home 
scope that is responsible for opening and closing it. That scope could 
be defined by a function or a module. But I'm not a theorist so can't 
make any general claims. I can see, though, how ref count could close a 
file sooner than if one waits until returning to some ultimate enclosing 
scope.

> (3) Any code that is saving tracebacks should assume that it is likely
> to cause trouble, unless it is using code that is explicitly
> documented to be robust in the face of this, just as any code that
> wants to share objects between multiple threads should assume that
> this is likely to cause trouble, unless it is using code that is
> explicitly documented to be robust in the face of this.
> 

Luckily there is not much need to save tracebacks.

> (4) Any code that catches exceptions should either return soon or
> clear the exception.  If it doesn't, the problem is not with the
> callee, but with the caller.
> 

Explicitly clear the exception? With sys.exc_clear?

> (5) You don't necessarily want a function that raises an exception to
> deallocate all of its resources before raising the exception, since
> you may want access to these resources for debugging, or what have you.
> 

No problem:

 >>> class MyFile(file):
	def __exit__(self, exc_type, exc_val, exc_tb):
		if exc_type is None:
			file.__exit__(self, None, None, None)
		return False

	
 >>> del f

Traceback (most recent call last):
   File "<pyshell#36>", line 1, in <module>
     del f
NameError: name 'f' is not defined
 >>> try:
	with MyFile("something", "w") as f:
		raise StandardError("")
except StandardError:
	print "Caught"

	
Caught
 >>> f.closed
False


But that is not very imaginative:

 >>> class MyFile(file):
	def __exit__(self, exc_type, exc_val, exc_tb):
		if exc_type is not None:
			self.my_last_posn = self.tell()
		return file.__exit__(self, exc_type, exc_val, exc_tb)

	
 >>> del f

Traceback (most recent call last):
   File "<pyshell#44>", line 1, in <module>
     del f
NameError: name 'f' is not defined
 >>> try:
	with MyFile("something", "w") as f:
		f.write("A line of text\n")
		raise StandardError("")
except StandardError:
	print "Caught"

	
Caught
 >>> f.closed
True
 >>> f.my_last_posn
16L

---
Lenard Lindstrom
<len-l at telus.net>

	



More information about the Python-list mailing list