In Java, my current bread-winning language, exceptions are caught mostly
because the compiler/language demands it. I haven't yet designed a
system in Java such as:
while(1):
try:
read
catch:
break
else:
...
Another way of putting it is, if the try-catch-else didn't exist would
anyone be terribly put out? (If not then the construct isn't much
used...)
Thanks,
Jerome.
--
Jerome Mrozak "Never buy a dog and bark for yourself"
go...@enteract.com --"Slippery" Jim DiGriz
(the Stainless Steel Rat)
have you written any Python code at all?
</F>
Oh yes they are -- an absolutely crucial and fundamental technique.
> In Java, my current bread-winning language, exceptions are caught mostly
> because the compiler/language demands it. I haven't yet designed a
To be specific: in Java, if a certain method's body can raise
certain exceptions it does not catch, you have to _declare_ this
as a part of the method's signature. A very good design choice
within a language hinging on compile-time static typechecking,
and vastly superior to C++'s semantics for exception declarations
(which were hampered by the need for backwards compatibility).
> Another way of putting it is, if the try-catch-else didn't exist would
> anyone be terribly put out? (If not then the construct isn't much
> used...)
Python programming would be utterly different (and much less fun)
if one could not use try/except. (try/finally could more easily
be replaced by a slightly different semantics on guaranteed
finalization of objects, and it's a pity a 'try' can't have one
or more 'except' clauses _followed_ by a 'finally' one, etc, etc,
but these are secondary issues).
Specifically: in Python, exceptions are NOT for 'exceptional'
conditions ONLY (as good programming style demands they be in
C++, and, ideally, in Java just as well). exceptions are the
NORMAL Python way to report on "I can't do this, Jim".
You want to exit from a deeply-nested loop, or recursion? Use
exceptions. You want to terminate a tree-walk over directories?
Use exceptions.
Perhaps the single most important issue is the design pattern
named (after a famous quote from Commodore Hopper, Cobol's
inventor) "It's easier to ask forgiveness than permission".
A typical setting for it: somebody asks, "How do I check that
a file exists?". What they most often MEAN by this: 'how do
I check that a file exists AND is authorized to be read by
the user currently running the program AND THEN actually go
and open the file for reading?" -- and the best answer to this
question is NOT, e.g.:
def open_if_ok1(filepath):
if os.access(filepath, os.R_OK):
return open(filepath, 'r')
else:
return None
Why not? Well, for example, the world is multi-tasked: there
is a small but non-null window of time between the instant
in which os.access gives you the go-ahead, and the following
instant in which you actually go and 'use' that permission!
The file *might* go away or get locked against reading in
that small window -- the kind of problem, connected with 'race
conditions', that's EXCEEDINGLY hard to pinpoint, reproduce,
and debug, when it comes up...
There is a simpler, safer, sounder way...:
def open_if_ok2(filepath):
try: return open(filepath, 'r')
except IOError: return None
"Just do it" -- making sure expected possible errors are
caught and handled in according with the semantic specs
(here, we assume, None is to be returned if the filepath
can't be opened for reading, for whatever reason).
Or, take another example. "Am I allowed to set attribute
foo of object bar to the Unicode string u'fee fie foo fum'"?
How do you check for *that*, when the object can have any
type, and, if it's an instance-object, its __setattr__ might
do whatever kinds of semantic checks on the attribute being
set and/or the value it's being set to...?
'Asking for permission' is basically unfeasible here. Much
better to 'ask for forgiveness' if needed, e.g.:
def setattr_ok(obj, attr, value):
try: setattr(obj, attr, value)
except (AttributeError, ValueError): return 0
else: return 1
(Some might prefer a wider 'except: return 0' clause, but
most often it's better to be specific in catching exceptions).
Alex
> I realize that Python allows me to catch exceptions. But being a
> novice
> I'm not sure if they are used much in the 'real world'.
...
> Another way of putting it is, if the try-catch-else didn't exist would
> anyone be terribly put out? (If not then the construct isn't much
> used...)
Yes. Yes. Yes.
Anyone who has done substantial programming in Python, Java, or C++ has
used exceptions extensively. If you haven't found a significant use for
exceptions, then you're either writing extremely trivial programs (ones
so trivial they cannot fail, which has to be _really_ trivial) or you're
not handling error conditions properly. Truth be told, handling
arbitrary error conditions properly is one of the more difficult things
to do in computer science. Exceptions, although they require a
significant change in the way you write code, make this a lot easier.
Draft Standard C++ programming without exceptions was obnoxious.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/ \ Love is not love which alters when it alteration finds
\__/ William Shakespeare, _Sonnets_, 116
Alcyone Systems' CatCam / http://www.catcam.com/
What do your pets do all day while you're at work? Find out.
Python and Delphi both have try-except and try-finally
but no try-except-finally. I once saw the person responsible
for this in Delphi explain why there was no try-except-finally,
in reply to a complaint about its non-existence. I'm not going
to try to convince you he was right, but at least in Delphi
it wasn't just an oversight, they considered it and finally
decided against it.
--
Oh, dejanews lets you add a sig - that's useful...
Sent via Deja.com
http://www.deja.com/
quoting myself from a recent post:
$ cd Python-2.0
$ more Misc/HISTORY
...
Release 0.9.6 (6 Apr 1992)
...
New features in 0.9.6:
- stricter try stmt syntax: cannot mix except and
finally clauses on 1 try
....
for more info, see e.g.
http://www.deja.com/getdoc.xp?AN=644277741
</F>
I would go further and say that 'except: return 0' should never be used,
since it would catch and ignore MemoryError, KeyboardInterrupt, SystemExit,
ComputerExplodingError, or any number of other exceptions that are totally
unrelated to the issue at hand and require careful handling and/or program
termination.
--
Rainer Deyke (ro...@rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor
An example of compulsion is java.lang.Integer.parseInt(), which throws a
NumberFormatException you *must* deal with or the program won't
compile. I'm aware of examples of Python such as (faking it here):
while 1:
try:
input = inputFileObject.readline()
catch EOF:
break
else:
process(input)
The point of the question is this -- is code like this sample a way of
exercising the try-catch, or is this an example of something I end up
doing all of the time because it is so much easier than the alternative?
Other posters to this question provided a fair sampling of examples.
Some, I'm disappointed to say, were, shall we say, not so supportive.
The long-range goal of my question is to determine for my satisfaction
whether it is worth while for me to spend my limited time pursuing
Python as a compliment to (whatever other skills I might have) or to go
with the apparently much greater flow and use those resources on Perl.
The 'exception' thing could be a determiner, esp. with nothing similar
in Perl, but only if I can use it in a *positive* way instead of just to
test a return value. Heck, Perl has 'die' for that kind of testing.
Thanks for your concern anyways.
Jerome.
--
The Python interpreter will throw exceptions. You are not obligated to
handle them. In some cases, you can prevent the exception from being thrown
in the first place.
For example, suppose you are trying to calculate the average of a sequence.
def average(l):
total = 0
for item in l:
total += item
total /= len(l)
When the length of the sequence is 0, this throws a ZeroDivisionError. You
can handle this with a try clause:
def average(l):
total = 0
for item in l:
total += item
try:
total /= len(l)
except ZeroDivisionError:
return 0
You can handle it with a guard condition:
def average(l):
total = 0
for item in l:
total += item
if len(l) == 0:
return 0
else:
return total / len(l)
Or you can ignore it altogether, assuming that you will never be passed an
empty sequence:
def average(l):
total = 0
for item in l:
total += item
total /= len(l)
This last option is actually the best in most cases. If the caller wants to
pass an empty sequence, the caller still has the option of catching the
ZeroDivisionError:
try:
avg = average([])
except ZeroDivisionError:
print 'Hello world!'
> [snip]
> When the length of the sequence is 0, this throws a ZeroDivisionError. You
> can handle this with a try clause:
>
> def average(l):
> total = 0
> for item in l:
> total += item
> try:
> total /= len(l)
> except ZeroDivisionError:
> return 0
>
> [snip]
>
> This last option is actually the best in most cases. If the caller wants to
> pass an empty sequence, the caller still has the option of catching the
> ZeroDivisionError:
>
> try:
> avg = average([])
> except ZeroDivisionError:
> print 'Hello world!'
>
If you enclose statements in a try/except clause, and assuming no
exception is thrown, what are the runtime penalties?
Roey
> def setattr_ok(obj, attr, value):
> try: setattr(obj, attr, value)
> except (AttributeError, ValueError): return 0
> else: return 1
There are dangers in that approach when the exception
being caught is a very common one such as AttributeError.
If the obj is such that calling setattr on it causes some
Python code to be executed, and there is a bug in that
code which causes an AttributeError to be raised, you'll
never know about it.
A similar problem occurs with Python's use of IndexError
to terminate a for-loop.
For that reason, I have mixed feelings about whether
the exception-as-normal-flow-control style of programming
is a good idea. It might be okay if you use a special-purpose
exception class created just for that particular use,
but abusing exceptions which normally indicate bugs is
asking for trouble, in my opinion.
> def open_if_ok2(filepath):
> try: return open(filepath, 'r')
> except IOError: return None
>
A minor gripe here - it would be more useful if Python
had some subclasses of IOError to distinguish between
different reasons for failure, so you can catch them
more selectively. If the reason is "the file doesn't
exist", you might want to do something to make it exist
and then try again. But if the reason is "the file exists
but the user doesn't have permission" or "someone put
peanut butter in the disk drive", you probably just want
to let the exception propagate.
--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg
I thought the overwhelming response was "YES!", but maybe I'm just
delirious.
> The long-range goal of my question is to determine for my satisfaction
> whether it is worth while for me to spend my limited time pursuing
> Python as a compliment to (whatever other skills I might have) or to go
> with the apparently much greater flow and use those resources on Perl.
> The 'exception' thing could be a determiner, esp. with nothing similar
> in Perl, but only if I can use it in a *positive* way instead of just to
> test a return value. Heck, Perl has 'die' for that kind of testing.
Perl has signal-trapping on top of the 'eval(...);if($@){...}' struct, on top
of being able to disguise the later as the much more recognisable:
: try {...}
: catch {...}
along with the ability to pass custom objects, in addition to the normal
strings, via the $@ variable. And although Python's implementation is
much more graceful, Perl can by all means accomplish the same task.
Both languages are extremely powerful and flexible. You won't be
limiting yourself with either language in terms of what you can
accomplish. As far as I can tell, the choice between Python and Perl is
more a matter of what you're comfortable with and which fits your
personality. I must have multiple personalities, because I won't
choose. =)
And besides, if you ask "What's better: Python or Perl?" in a python NG,
what answer do you expect?
Try both. Perl is a significantly different style from most people's
experience, unless that experience consisted highly of Unix shell
programming. Python may suit your current skills (whatever, if any,
they might be) better. Don't let us decide for you.
And yes, exceptions are used voluntarily and frequently by thousands of
programmers daily because it makes their jobs easier and they can be
fun.
And if THAT doesn't answer your question... =)
--
-Tim Hammerquist <ti...@cpan.org>
Not all who wander are lost.
-- J.R.R. Tolkien
> A minor gripe here - it would be more useful if Python
> had some subclasses of IOError to distinguish between
> different reasons for failure, so you can catch them
> more selectively. If the reason is "the file doesn't
> exist", you might want to do something to make it exist
> and then try again. But if the reason is "the file exists
> but the user doesn't have permission" or "someone put
> peanut butter in the disk drive", you probably just want
> to let the exception propagate.
I suppose one of the issues is constructing a reasonable class
hierarchy that would portably represent the common failure mores.
It's not necessarily portable, but even if you can't distinguish at
the exception level, there's nothing stopping the exception handling
code from examining the associated object with the exception, and if
the code doesn't match the case it wants to handle, just using "raise"
to re-raise the same exception and let it continue propagating.
In the case of IOError that does imply parsing a string and assuming
it starts with [Errno #], which is sort of crufty. But other
exceptions (such as those from win32all) are fairly standardized as a
tuple with the code as the first element - something I also tend to do
with my own user exceptions in my code.
Thus, you can get a reasonable mix in terms of design between the
exception class hierarchy and then the finer grained specific failure
within a class of exceptions.
--
-- David
--
/-----------------------------------------------------------------------\
\ David Bolen \ E-mail: db...@fitlinxx.com /
| FitLinxx, Inc. \ Phone: (203) 708-5192 |
/ 860 Canal Street, Stamford, CT 06902 \ Fax: (203) 316-5150 \
\-----------------------------------------------------------------------/
Ah, I see what you mean. No, there's never a case where you
really *have* to catch an exception. You always have the
option of ignoring exceptions; an exception which isn't
caught anywhere will simply cause the program to abort
with a traceback.
Sometimes you will want to catch exceptions, but those cases
are very rare, in my experience. Most of the time you can
write code without thinking about exceptions at all.
> I'm aware of examples of Python such as (faking it here):
>
> while 1:
> try:
> input = inputFileObject.readline()
> catch EOF:
> break
> else:
> process(input)
Python doesn't report end-of-file by means of an exception;
it returns an empty string.
It does report I/O errors such as failing to open a file
with an exception, which is one of the few cases that you
will probably want to catch. You don't necessarily have
to put a try-except around every file open, though, and
that's probably not the best thing to do. A single
try-except somewhere high up in your program's logic
to catch any failures and report them to the user is
usually sufficient.
Hope that helps,
] In the case of IOError that does imply parsing a string and assuming
] it starts with [Errno #], which is sort of crufty. But other
] exceptions (such as those from win32all) are fairly standardized as a
] tuple with the code as the first element - something I also tend to do
] with my own user exceptions in my code.
Note that now that the standard exceptions are classes, IOError instances
have an errno attribute, which is even nicer than using tuple values.
try:
f = open(filename, 'r'):
except IOError, exc:
if exc.errno == errno.ENOENT:
pass
else:
raise
Yeah, except that the error numbers it gives you
seem to be platform-dependent.
| Yeah, except that the error numbers it gives you
| seem to be platform-dependent.
the idea is to compare them to the symbolic constants in the errno
module.
-- erno
Minimal, from what I've heard, but I don't feel like doing any
benchmarking right now.
--
--- Aahz (Copyright 2000 by aa...@pobox.com)
Androgynous poly kinky vanilla queer het <*> http://www.rahul.net/aahz/
Hugs and backrubs -- I break Rule 6
This is a signature anti-virus.
Please stop the spread of signature viruses!
Depends on how much you're doing. If the amount of
work is minimal, the overhead can easily get as big
as 10% or so...:
import time
def clean(n):
tot = 0L
for i in range(n):
tot += i
return tot
def safe(n):
tot = 0L
for i in range(n):
try: tot += i
except ValueError: pass
return tot
start = time.clock()
tot = clean(100000)
stend = time.clock()
print 'clean:', stend-start
start = time.clock()
tot = safe(100000)
stend = time.clock()
print 'safe:', stend-start
D:\PySym>python ddd.py
clean: 0.650930034144
safe: 0.724842480024
D:\PySym>python ddd.py
clean: 0.645219254062
safe: 0.726402175024
D:\PySym>python ddd.py
clean: 0.651437081686
safe: 0.726812003533
D:\PySym>
So, putting a try/except around (say) each single
addition *does* have measurable impact. A grain
a _tad_ less fine than this might be better, if
performance is an important issue.
Alex