简体   繁体   中英

How to handle exceptions correctly?

I don't quite understand yet how to correctly use exceptions in Python. I want to process the data I can't completely trust (they are prone to change, and if they change, script may break). Let's say I process a webpage using BeautifulSoup. If author of the website make some changes to his website, some statements may rise exception. Let's look at this code example:

data = urllib2.urlopen('http://example.com/somedocument.php').read()
soup = BeautifulSoup(data, convertEntities="html")

name = soup.find('td', text=re.compile(r'^Name$')).parent.nextSibling.string

print name

Now, if soup.find() fail because owner of that website will change content of the website and rename cell Name to Names , an exception AttributeError: 'NoneType' object has no attribute 'parent' will be raised. But I don't mind. I expect that some data won't be available, I just want to proceed and use what variables I have available (of course there will be some data I NEED. and if they are unavailable I will simply exit.

Only solution I came up with is:

try: name = soup.find('td', text=re.compile(r'^Name$')).parent.nextSibling.string
except AttributeError: name = False
try: email = soup.find('td', text=re.compile(r'^Email$')).parent.nextSibling.string
except AttributeError: email = False
try: phone = soup.find('td', text=re.compile(r'^Phone$')).parent.nextSibling.string
except AttributeError: phone = False

if name: print name
if email: print email
if phone: print phone

Is there any better way, or should I just continue making try-except for every similar statement? It doesn't look very nice at all.

EDIT: Best solution for me would be like this:

try:
    print 'do some stuff here that may throw and exception'
    print non_existant_variable_that_throws_an_exception_here
    print 'and few more things to complete'
except:
    pass

This would be great, but pass will skip anything in try code block, so and few more things to complete will never be printed. If there was something like pass, but it would just ignore the error and continue executing, it would be great.

Firstly, if you don't mind the exception you can just let it pass:

try:
    something()
except AttributeError:
    pass

but never do this as it is will let all errors pass:

try:
    something()
except Exception:
    pass

As for your code sample, perhaps it could be tidied up with something like this:

myDict = {}

for item in ["Name", "Email", "Phone"]:
    try:
        myDict[item] = soup.find('td', text=re.compile(r'^%s$' % item)).parent.nextSibling.string
    except Attribute
        myDict[item] = "Not found"

for item in ["Name", "Email", "Phone"]:
    print "%s: %s" % (item, myDict[item])

Have you tried using a try/finally statement instead?

http://docs.python.org/tutorial/errors.html#defining-clean-up-actions

Example from the docs:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print "division by zero!"
...     else:
...         print "result is", result
...     finally:
...         print "executing finally clause"

So, to use your example:

try:
    do_some_stuff_here_that_may_throw_an_exception()
except someError:
    print "That didn't work!"
else:
    print variable_that_we_know_didnt_throw_an_exception_here
finally:
    print "finishing up stuff"

"finally" will always excecute, so that's where you can put your "finishing up" stuff.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM