57

If I run the code:

connection = manager.connect("I2Cx")

The program crashes and reports a KeyError because I2Cx doesn't exist (it should be I2C).

But if I do:

try:
    connection = manager.connect("I2Cx")
except Exception, e:
    print e

It doesn't print anything for e. I would like to be able to print the exception that was thrown. If I try the same thing with a divide by zero operation it is caught and reported properly in both cases. What am I missing here?

spizzak
  • 1,087
  • 1
  • 11
  • 17
  • 4
    Side note: Unless you need pre-2.5 compatibility, you should write `except Exception as e:` instead of `except Exception, e:`. – abarnert Apr 22 '13 at 18:47

7 Answers7

95

If it's raising a KeyError with no message, then it won't print anything. If you do...

try:
    connection = manager.connect("I2Cx")
except Exception as e:
    print repr(e)

...you'll at least get the exception class name.

A better alternative is to use multiple except blocks, and only 'catch' the exceptions you intend to handle...

try:
    connection = manager.connect("I2Cx")
except KeyError as e:
    print 'I got a KeyError - reason "%s"' % str(e)
except IndexError as e:
    print 'I got an IndexError - reason "%s"' % str(e)

There are valid reasons to catch all exceptions, but you should almost always re-raise them if you do...

try:
    connection = manager.connect("I2Cx")
except KeyError as e:
    print 'I got a KeyError - reason "%s"' % str(e)
except:
    print 'I got another exception, but I should re-raise'
    raise

...because you probably don't want to handle KeyboardInterrupt if the user presses CTRL-C, nor SystemExit if the try-block calls sys.exit().

Halee
  • 492
  • 9
  • 15
Aya
  • 39,884
  • 6
  • 55
  • 55
  • I think his problem was more the `catch` part than the actual printing ... but yeah this solves that problem also – Joran Beasley Apr 22 '13 at 18:36
  • 1
    @JoranBeasley The `catch` is more likely a typo, since the OP would've gotten a different error had that been in the real code. – Aya Apr 22 '13 at 18:41
  • 1
    +1. But `KeyboardInterrupt` and `SystemExit` aren't subclasses of `Exception`, so your last sentence is misleading. – abarnert Apr 22 '13 at 18:48
  • @abarnert Actually it's the "catch all exceptions" which is misleading, so I've changed `except Exception, e:`, to `except:`. Looks like you have to consult `sys.exc_info()` to get the exception in a bare `except:` clause, so it's probably simpler to omit it. – Aya Apr 22 '13 at 18:58
  • 1
    @Aya: If you want to catch all exception types, including `KeyboardInterrupt` and `SystemExit`, catch `BaseException` rather than `Exception`. This still won't handle bare-string exceptions (or exceptions of unrelated types that you've somehow managed to raise behind the interpreter's back—pretty easy to do accidentally in a C extension module, not so easy to do even on purpose in pure Python); for that, you do need a bare `except`. – abarnert Apr 22 '13 at 19:04
  • @abarnert Yeah. I was considering using `BaseException`, but I decided that still doesn't technically catch all exceptions. Looks like (at least in Python 2.7.3) you can't raise bare strings any more, but by the looks of the error message `TypeError: exceptions must be old-style classes or derived from BaseException, not str` you can still raise old-style classes. – Aya Apr 22 '13 at 19:09
  • @Aya: I didn't want to assume 2.7, given the 2.4-style except clause in the OP's code… (But I thought it safe to assume 2.2, at least.) Anyway, the point is that your original code was catching `Exception` an then reraising it to avoid swallowing `KeyboardInterrupt` and `SystemExit`. That isn't necessary; if you catch `Exception` you won't swallow those. That's all. It's fine the way it is now. – abarnert Apr 22 '13 at 19:11
  • @abarnert TBH, I still use the 2.4-style `except` clause in 2.7.3, but only because I wasn't aware of the newer syntax. Still, it's not unreasonable to assume that most people using 2.x will be using 2.6.x or 2.7.x. – Aya Apr 22 '13 at 19:15
  • @Aya: Read [PEP 3110](http://www.python.org/dev/peps/pep-3110/). The comma style is ambiguous between expression-and-target and tuple-expression. Of course the interpreter has some arbitrary rules to resolve the ambiguity, but programmers don't memorize those rules; we read it properly in simple cases, but guess wildly in edge cases. – abarnert Apr 22 '13 at 19:44
  • @abarnert Huh. I wasn't even aware you could catch multiple exception types in a single `except` clause, well, not without catching a superclass of those types, and I can't actually see many cases where it would be particularly useful to do so. An exception handler is usually going to be specific to a particular exception class, or general enough to just `catch Exception`. You happen to know if the `catch Type1, Type2` idiom is used anywhere in the standard library? – Aya Apr 22 '13 at 19:59
  • 1
    Here's [one example](http://hg.python.org/cpython/file/2.7/Lib/asyncore.py#l84) in the stdlib. I tend to use it most often when third-party library foo-0.88 raised a `ValueError`, but 0.89 raises a `TypeError` or a `foo.FooError`. (The alternatives are two copy-pasted `except` blocks, or an `except Exception as e:` with `if isinstance(e, (ValueError, TypeError)): raise`, or requiring foo-0.89 or later for no good reason…) – abarnert Apr 22 '13 at 20:21
20

I am using Python 3.6 and using a comma between Exception and e does not work. I need to use the following syntax (just for anyone wondering)

try:
    connection = manager.connect("I2Cx")
except KeyError as e:
    print(e.message)
ajpieri
  • 306
  • 3
  • 11
6

You should consult the documentation of whatever library is throwing the exception, to see how to get an error message out of its exceptions.

Alternatively, a good way to debug this kind of thing is to say:

except Exception, e:
    print dir(e)

to see what properties e has - you'll probably find it has a message property or similar.

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
2

You can also try to use get(), for example:

connection = manager.connect.get("I2Cx")

which won't raise a KeyError in case the key doesn't exist.

You may also use second argument to specify the default value, if the key is not present.

kenorb
  • 155,785
  • 88
  • 678
  • 743
1

If you don't want to handle error just NoneType and use get() e.g.:

manager.connect.get("")
kenorb
  • 155,785
  • 88
  • 678
  • 743
Amrit
  • 11
  • 1
0

I dont think python has a catch :)

try:
    connection = manager.connect("I2Cx")
except Exception, e:
    print e
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
-2

Try print(e.message) this should be able to print your exception.

try:
    connection = manager.connect("I2Cx")
except Exception, e:
    print(e.message)
Mic
  • 345
  • 1
  • 3
  • 9