@@ -111,30 +111,40 @@ except:
111111-------
112112
113113Python 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
140150Exceptions
@@ -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
194207several files in a loop), or just let the exception filter upwards to *its *
195208caller.
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