Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bec04a9

Browse files
committed
Merged revisions 84719 via svnmerge from
svn+ssh://[email protected]/python/branches/py3k ........ r84719 | r.david.murray | 2010-09-11 14:12:25 -0400 (Sat, 11 Sep 2010) | 2 lines #9608, #8518 : clarify and improve discussion of exceptions in howto. ........
1 parent 42bc691 commit bec04a9

1 file changed

Lines changed: 53 additions & 34 deletions

File tree

Doc/howto/doanddont.rst

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -111,30 +111,40 @@ except:
111111
-------
112112

113113
Python has the ``except:`` clause, which catches all exceptions. Since *every*
114-
error in Python raises an exception, this makes many programming errors look
115-
like runtime problems, and hinders the debugging process.
114+
error in Python raises an exception, using ``except:`` can make many
115+
programming errors look like runtime problems, which hinders the debugging
116+
process.
116117

117-
The following code shows a great example::
118+
The following code shows a great example of why this is bad::
118119

119120
try:
120121
foo = opne("file") # misspelled "open"
121122
except:
122123
sys.exit("could not open file!")
123124

124-
The second line triggers a :exc:`NameError` which is caught by the except
125-
clause. The program will exit, and you will have no idea that this has nothing
126-
to do with the readability of ``"file"``.
125+
The second line triggers a :exc:`NameError`, which is caught by the except
126+
clause. The program will exit, and the error message the program prints will
127+
make you think the problem is the readability of ``"file"`` when in fact
128+
the real error has nothing to do with ``"file"``.
127129

128-
The example above is better written ::
130+
A better way to write the above is ::
129131

130132
try:
131-
foo = opne("file") # will be changed to "open" as soon as we run it
133+
foo = opne("file")
132134
except IOError:
133135
sys.exit("could not open file")
134136

135-
There are some situations in which the ``except:`` clause is useful: for
136-
example, in a framework when running callbacks, it is good not to let any
137-
callback disturb the framework.
137+
When this is run, Python will produce a traceback showing the :exc:`NameError`,
138+
and it will be immediately apparent what needs to be fixed.
139+
140+
.. index:: bare except, except; bare
141+
142+
Because ``except:`` catches *all* exceptions, including :exc:`SystemExit`,
143+
:exc:`KeyboardInterrupt`, and :exc:`GeneratorExit` (which is not an error and
144+
should not normally be caught by user code), using a bare ``except:`` is almost
145+
never a good idea. In situations where you need to catch all "normal" errors,
146+
such as in a framework that runs callbacks, you can catch the base class for
147+
all normal exceptions, :exc:`Exception`.
138148

139149

140150
Exceptions
@@ -152,51 +162,60 @@ The following is a very popular anti-idiom ::
152162
sys.exit(1)
153163
return open(file).readline()
154164

155-
Consider the case the file gets deleted between the time the call to
156-
:func:`os.path.exists` is made and the time :func:`open` is called. That means
157-
the last line will throw an :exc:`IOError`. The same would happen if *file*
158-
exists but has no read permission. Since testing this on a normal machine on
159-
existing and non-existing files make it seem bugless, that means in testing the
160-
results will seem fine, and the code will get shipped. Then an unhandled
161-
:exc:`IOError` escapes to the user, who has to watch the ugly traceback.
165+
Consider the case where the file gets deleted between the time the call to
166+
:func:`os.path.exists` is made and the time :func:`open` is called. In that
167+
case the last line will raise an :exc:`IOError`. The same thing would happen
168+
if *file* exists but has no read permission. Since testing this on a normal
169+
machine on existent and non-existent files makes it seem bugless, the test
170+
results will seem fine, and the code will get shipped. Later an unhandled
171+
:exc:`IOError` (or perhaps some other :exc:`EnvironmentError`) escapes to the
172+
user, who gets to watch the ugly traceback.
162173

163-
Here is a better way to do it. ::
174+
Here is a somewhat better way to do it. ::
164175

165176
def get_status(file):
166177
try:
167178
return open(file).readline()
168-
except (IOError, OSError):
169-
print("file not found")
179+
except EnvironmentError as err:
180+
print("Unable to open file: {}".format(err))
170181
sys.exit(1)
171182

172-
In this version, \*either\* the file gets opened and the line is read (so it
173-
works even on flaky NFS or SMB connections), or the message is printed and the
174-
application aborted.
183+
In this version, *either* the file gets opened and the line is read (so it
184+
works even on flaky NFS or SMB connections), or an error message is printed
185+
that provides all the available information on why the open failed, and the
186+
application is aborted.
175187

176-
Still, :func:`get_status` makes too many assumptions --- that it will only be
177-
used in a short running script, and not, say, in a long running server. Sure,
178-
the caller could do something like ::
188+
However, even this version of :func:`get_status` makes too many assumptions ---
189+
that it will only be used in a short running script, and not, say, in a long
190+
running server. Sure, the caller could do something like ::
179191

180192
try:
181193
status = get_status(log)
182194
except SystemExit:
183195
status = None
184196

185-
So, try to make as few ``except`` clauses in your code --- those will usually be
186-
a catch-all in the :func:`main`, or inside calls which should always succeed.
197+
But there is a better way. You should try to use as few ``except`` clauses in
198+
your code as you can --- the ones you do use will usually be inside calls which
199+
should always succeed, or a catch-all in a main function.
187200

188-
So, the best version is probably ::
201+
So, an even better version of :func:`get_status()` is probably ::
189202

190203
def get_status(file):
191204
return open(file).readline()
192205

193-
The caller can deal with the exception if it wants (for example, if it tries
206+
The caller can deal with the exception if it wants (for example, if it tries
194207
several files in a loop), or just let the exception filter upwards to *its*
195208
caller.
196209

197-
The last version is not very good either --- due to implementation details, the
198-
file would not be closed when an exception is raised until the handler finishes,
199-
and perhaps not at all in non-C implementations (e.g., Jython). ::
210+
But the last version still has a serious problem --- due to implementation
211+
details in CPython, the file would not be closed when an exception is raised
212+
until the exception handler finishes; and, worse, in other implementations
213+
(e.g., Jython) it might not be closed at all regardless of whether or not
214+
an exception is raised.
215+
216+
The best version of this function uses the ``open()`` call as a context
217+
manager, which will ensure that the file gets closed as soon as the
218+
function returns::
200219

201220
def get_status(file):
202221
with open(file) as fp:

0 commit comments

Comments
 (0)