What is the best way to write try except in Python?

情到浓时终转凉″ 提交于 2020-12-31 23:47:10

问题


Suppose I have a code snippet as following

r = requests.post(url, data=values, files=files)

Since this is making a network request, a bunch of exceptions can be thrown from this line. For completeness of the argument, I could also have file reads, sending emails, etc. To encounter for such errors I do

try:
  r = requests.post(url, data=values, files=files)
  if r.status_code != 200:
    raise Exception("Could not post to "+ url)
except Exception as e:
  logger.error("Error posting to " + url)

There are two problems which I see with this approach.

  1. I have just handled a generic exception and don't know what exact exception would be raised by this line, what is the best way to find it in python.
  2. This makes the code look ugly, which is non pythonic but fine, as long as its robust and handles all the cases.

I am wondering what would be the best way to handle exceptions in python.


回答1:


The best way to write try-except -- in Python or anywhere else -- is as narrow as possible. It's a common problem to catch more exceptions than you meant to handle!

In particular, at a minimum, I'd re-write your example code as something like:

try:
  r = requests.post(url, data=values, files=files)
except Exception as e:
  logger.error("Error posting to %r: %s" % (url, e))
  raise
else:
  if r.status_code != 200:
    logger.error("Could not to %r: HTTP code %s" % (url, r.status_code))
  raise RuntimeError("HTTP code %s trying to post to %r" % (r.status_code, url))

This embodies several best-practices, such as: detailed error messages, always re-raise exceptions you don't know how to specifically handle (after logging error messages with more details as well as the exception), never raise something as generic as Exception, &c -- and, crucially, catch exceptions only on the narrowest part of code you possibly can, that's what the else: clause in try/except is for!-)

If and when you do expect -- and know how to handle -- specific exceptions, so much the better -- you put other except ThisSpecificProblem as e: clauses before the generic except Exception clause which logs and re-raises. But (from the Zen of Python -- import this at a Python interpreter prompt!) -- "Errors should never pass silently. // Unless explicitly silenced."... and you should only "explicitly silence" errors you fully expect, and fully know how to handle!




回答2:


I have just handled a generic exception and don't know what exact exception would be raised by this line, what is the best way to find it in python.

As always, the answer is to look at the documentation:

In the event of a network problem (e.g. DNS failure, refused connection, etc), Requests will raise a ConnectionError exception.

In the rare event of an invalid HTTP response, Requests will raise an HTTPError exception.

If a request times out, a Timeout exception is raised.

If a request exceeds the configured number of maximum redirections, a TooManyRedirects exception is raised.

All exceptions that Requests explicitly raises inherit from requests.exceptions.RequestException.

Code that raises exceptions (especially if there are custom exceptions) is documented. You can also have a look at the source if the documentation is not explicit.

Your code is fine, except you should avoid generic except clauses as these can hide other problems with your code. You should except those exceptions that you can predict, and then let the others "rise up" until caught/logged.




回答3:


Well, answering your first question, what exact exception would be raised by this line, you are one step away.

You already call except Exception as e, but you don't use e anywhere. e contains the information about your exception, so just add a little print statement

print e

And it works:

>>> try:
...     x = int(raw_input('Input: '))
... except Exception as e:
...     print e
... 
Input: 5t
invalid literal for int() with base 10: '5t'
>>> 

I don't exactly see what you're asking in the 2nd, you say it is ugly/non-pythonic, but then you say it is fine. Yes, it is fine, and it is also quite pythonic, in my opinion.




回答4:


You should try avoiding using except Exception as e: as much as possible.

For clarity you can create a custom exception class which takes care of your error code = 200 scenario.

class PostingError(Exception):
    pass

And then raise PostingError only. Try catching this error only. By catching all kinds of error, you might be catching wrong information. For example even a memory error might be caught and displayed as a "Error posting to URL".

So this is how it would look like finally

try:
  r = requests.post(url, data=values, files=files)
  if r.status_code != 200:
    raise PostingError("Could not post to "+ url)
except PostingError as e:
  logger.error(e)


来源:https://stackoverflow.com/questions/27586886/what-is-the-best-way-to-write-try-except-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!