如何正确处理异常?

4 投票
2 回答
3045 浏览
提问于 2025-04-16 18:12

我还不太明白如何在Python中正确使用异常。我想处理一些我不能完全信任的数据(这些数据可能会变化,如果变化了,脚本可能会出错)。比如说,我用BeautifulSoup处理一个网页。如果网站的作者对网站做了一些修改,有些代码就可能会出现异常。我们来看这个代码示例:

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

现在,如果 soup.find() 失败了,因为网站的拥有者把内容改了,把单元格 Name 改成了 Names,就会出现一个异常 AttributeError: 'NoneType' object has no attribute 'parent'。但我并不在意!我预料到有些数据可能无法获取。我只想继续使用我能得到的变量(当然,有些数据是我必须的,如果这些数据不可用,我会直接退出程序)。

我想到的唯一解决办法是:

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

有没有更好的方法,还是我应该继续为每个类似的语句写try-except?这样看起来并不太好。

编辑:对我来说,最好的解决方案是这样的:

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

这听起来不错,但 pass 会跳过 try 代码块中的所有内容,所以 and few more things to complete 将永远不会被打印出来。如果有一种类似于pass的方式,但它只是忽略错误并继续执行,那就太好了。

2 个回答

1

你有没有试过用try/finally语句呢?

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

这是文档里的一个例子:

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

那么,针对你的例子:

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”部分总是会执行,所以你可以把“收尾工作”放在这里。

4

首先,如果你不在意这个异常,你可以让它继续运行:

try:
    something()
except AttributeError:
    pass

但千万不要这样做,因为这样会让所有的错误都被忽略:

try:
    something()
except Exception:
    pass

至于你的代码示例,也许可以用下面的方式整理一下:

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])

撰写回答