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