Index: Doc/howto/doanddont.rst =================================================================== --- Doc/howto/doanddont.rst (revision 84542) +++ Doc/howto/doanddont.rst (working copy) @@ -111,32 +111,39 @@ ------- Python has the ``except:`` clause, which catches all exceptions. Since *every* -error in Python raises an exception, this makes many programming errors look -like runtime problems, and hinders the debugging process. +error in Python raises an exception, using ``except:`` can make many +programming errors look like runtime problems, which hinders the debugging +process. -The following code shows a great example:: +The following code shows a great example of why this is bad:: try: foo = opne("file") # misspelled "open" except: sys.exit("could not open file!") -The second line triggers a :exc:`NameError` which is caught by the except -clause. The program will exit, and you will have no idea that this has nothing -to do with the readability of ``"file"``. +The second line triggers a :exc:`NameError`, which is caught by the except +clause. The program will exit, and the error message the program prints will +make you think the problem is the readability of ``"file"`` when in fact +the real error has nothing to do with ``"file"``. -The example above is better written :: +A better way to write the above is :: try: foo = opne("file") # will be changed to "open" as soon as we run it except IOError: sys.exit("could not open file") -There are some situations in which the ``except:`` clause is useful: for -example, in a framework when running callbacks, it is good not to let any -callback disturb the framework. +When this is run, Python will produce a traceback showing the :exc:`NameError`, +and it will be immediately apparent what needs to be fixed. +Because ``except:`` catches *all* errors, including :exc:`SystemExit`, +:exc:`KeyboardInterrupt`, and :exc:`GeneratorExit` (which isn't even an error), +using ``except:`` is almost never a good idea. In situations where you need to +catch all "normal" errors, such as in a framework that runs callbacks, you can +catch the base class for all normal exceptions, :exc:`Exception`. + Exceptions ========== @@ -160,7 +167,7 @@ results will seem fine, and the code will get shipped. Then an unhandled :exc:`IOError` escapes to the user, who has to watch the ugly traceback. -Here is a better way to do it. :: +Here is a somewhat better way to do it. :: def get_status(file): try: @@ -173,31 +180,38 @@ works even on flaky NFS or SMB connections), or the message is printed and the application aborted. -Still, :func:`get_status` makes too many assumptions --- that it will only be -used in a short running script, and not, say, in a long running server. Sure, -the caller could do something like :: +But even this version of :func:`get_status` makes too many assumptions --- that +it will only be used in a short running script, and not, say, in a long running +server. Sure, the caller could do something like :: try: status = get_status(log) except SystemExit: status = None -So, try to make as few ``except`` clauses in your code --- those will usually be -a catch-all in the :func:`main`, or inside calls which should always succeed. +You should try to use as few ``except`` clauses in your code as you can --- +those will usually be a catch-all in a main function, or inside calls which +should always succeed. -So, the best version is probably :: +So, an even better version is probably :: def get_status(file): return open(file).readline() -The caller can deal with the exception if it wants (for example, if it tries +The caller can deal with the exception if it wants (for example, if it tries several files in a loop), or just let the exception filter upwards to *its* caller. -The last version is not very good either --- due to implementation details, the -file would not be closed when an exception is raised until the handler finishes, -and perhaps not at all in non-C implementations (e.g., Jython). :: +But the last version still has a serious problem --- due to implementation +details in CPython, the file would not be closed when an exception is raised +until the exception handler finishes; and, worse, in other implementations +(e.g., Jython) it might not be closed at all regardless of whether or not +an exception is raised. +The best version of this function uses the ``open()`` call as a context +manager, which will ensure that the file gets closed as soon as the +function returns :: + def get_status(file): with open(file) as fp: return fp.readline()