Exceptions and the Python 2 except syntax
The comma syntax, string exceptions, sys.exc_info, and a mechanical rewrite to the Python 3 form that a compiler would catch.
The comma form
# Python 2
try:
value = int(raw_input("number: "))
except ValueError, exc: # binds the exception to exc
print "bad number:", exc
except (IOError, OSError), exc:
print "io problem:", exc
except Exception, exc:
raise RuntimeError("wrapped: %s" % exc)# Python 3 - identical semantics, different syntax
try:
value = int(input("number: "))
except ValueError as exc:
print("bad number:", exc)
except (IOError, OSError) as exc:
print("io problem:", exc)
except Exception as exc:
raise RuntimeError("wrapped: %s" % exc) from excexcept E, ebecameexcept E as e. The comma form is a syntax error in Python 3, so it is caught by the parser.raise X, argsbecameraise X(args)in 2.6 and was removed in 3.raise E, ewith three arguments (raise E, V, T) is gone entirely; usewith_tracebackinstead.
String exceptions and exc_info
def parse(text):
if not text:
raise "empty input" # legal in Python 2.5 and earlier only
return int(text)
try:
parse("")
except ValueError:
print "caught"
try:
1 / 0
except ZeroDivisionError:
import sys
kind, value, tb = sys.exc_info()
print kind, value
# Python 2 keeps the last exception alive until the next one or the end of the except block
del tb⚠️
In Python 2 an exception variable leaks out of the
except block and holds a reference to the traceback, which keeps frames and their locals alive. Delete it explicitly (del exc) in long-running processes, or you will chase a memory leak that has nothing to do with your own objects.A mechanical rewrite
| Python 2 | Python 3 |
|---|---|
except E, e: | except E as e: |
raise E, v | raise E(v) |
raise E, v, tb | raise E(v).with_traceback(tb) |
raise "message" | raise Exception("message") |
StandardError | Exception |
sys.exc_type | sys.exc_info()[0] |
bare except: swallowing everything | Still legal, still a bug in most cases |
# 2to3 handles the syntax; review every change it makes
2to3 -w -n app/ | tee 2to3.log
# then look for the patterns it deliberately leaves alone
grep -rn "except:" app/ | grep -v "except Exception"The compiler catches the syntax changes. What it does not catch is semantics: an except that was silently swallowing everything still swallows everything, and a bare except: also caught KeyboardInterrupt and SystemExit.
FAQ
Did Python 2 allow multiple exception types on one line?
Yes, as a tuple:
except (ValueError, TypeError), e:. The tuple must be parenthesised, since a tuple of types is the only accepted form.Why does my exception handler hold memory after it finishes?
In Python 2 the traceback is kept alive by the exception variable and by
sys.exc_info() until the next exception. Explicitly del the variable inside the handler if the process is long-lived.Related
Files, the codecs module and text vs binary I/O Migrating to Python 3
Last refreshed 2026-09-18.