如何在Python中正确使用try、except、else

17

所以我想知道编写try except语句的正确方法。我对Python中的错误处理还不熟悉。

选项1

try:
    itemCode = items["itemCode"]
    dbObject=db.GqlQuery("SELECT * FROM %s WHERE code=:1" % dbName,itemCode).get()
    dbObject.delete() 
except AttributeError:
    print "There's no item with that code"
except KeyError:
    print "Bad parameter name"
except:
    print "Unknow error" 

选项2

try:
    itemCode = items["itemCode"]
except KeyError:
    print "Bad parameter name"
else:    
    dbObject=db.GqlQuery("SELECT * FROM %s WHERE code=:1" % dbName,itemCode).get()
    try:    
        dbObject.delete() 
    except AttributeError:
        print "There's no item with that code"
    except:
        print "Unknow error" 

选项3 你还能想到更好的选项吗。

选项1,我们可以看到我将所有代码都包裹在try块中。 选项2,它使用嵌套块。 它在特定行语句上引发异常。

如果有错误,我会很高兴了解。


我不完全理解你的问题。在我看来,你的主要问题似乎是理解try, except, else, finally如何工作。这样说对吗?如果是的话,我可以提供一个解释这个的例子。 - inspectorG4dget
@inspectorG4dget - 我认为问题不在于它们如何工作(两个示例都是有效的),而是一个风格偏好的问题。 - g.d.d.c
我不明白为什么你要在“try:”块和“else:”块中删除对象,我有什么遗漏或者这样做没有意义吗? - Gareth Latty
2
你应该使用 if dbObject is not None: dbObject.delete() 而不是在此处捕获 AttributeError。 - jfs
@inspectorG4dget Lattyware这是关于编码风格的问题。代码的功能并不重要。J.F. Sebastian。我认为这是另一个主题,涉及到使用if语句与try语句的区别。 - john.dou.2011
选项1是明显的赢家。它没有嵌套,自我记录并且非常易于理解。 - ncmathsadist
3个回答

5

根据Python之禅,“扁平比嵌套好”。一般情况下,我会选择选项#1的风格,但我有点困惑于dbObject=db.GqlQuery("SELECT....dbObject.delete()是否会引发AttributeError。无论如何,你不应该多次调用dbObject.delete()


我的错,我修复了双重删除。dbObject.delete()引发了AttributeError。 - john.dou.2011
捕获所有错误并通过简单的“未知错误”消息隐藏它们并不是一个好主意。当您看到这样的错误消息时,很难理解发生了什么。 - cleg
@cleg 这是为了我不知道的错误。当它们出现时,我会捕捉到它们。 - john.dou.2011
1
@john.dou.2011 异常处理的思想是,如果您不知道错误和如何处理它,则将其传播到可能能够处理它的位置,尽管您正在打印“未知错误”,但我认为 cleg 指出了这很容易被忽略,因此可能会发生奇怪的事情... - Jon Clements
@john.dou.2011 — 看看我的例子。except StandardError — 就是这样。在这个例子中,所有的错误都被处理了,但更有用的例子被打印出来了。你可以使用 traceback 模块中的 format_exc() 函数添加更多细节。在日志中看到完整的堆栈跟踪非常有用 :) - cleg
显示剩余3条评论

0
简单-这取决于情况。如果您确定会遇到哪些异常,可以坚持使用1),而且实际上有90%的情况是如此。第二种方法很有用,如果您知道许多代码例程可能引发相同的异常类型。

-1

我更喜欢使用带有验证的字典的 get 方法,而不是捕获 KeyError 。

itemCode = items.get("itemCode") # itemCode will be None, if no such key
if itemCode is not None:
    print "code missing"

这不是“通用”解决方案(请参见我的答案评论),但在这种情况下它会有所帮助。

而且在第一种情况下,我不明白为什么你要尝试删除两次。

try:
    itemCode = items.get("itemCode") # itemCode will be None, if no such key
    if itemCode is not None:
        print "code missing"
    dbObject=db.GqlQuery("SELECT * FROM %s WHERE code=:1" % dbName,itemCode).get()
    dbObject.delete() 
except AttributeError:
    print "There's no item with that code"
except StandardError as ex:    # good idea to be prepared to handle various fails
    print "Unexpected error deleting item {}".format(ex)

另外,不要忘记 Python 有最终部分。有时候它非常方便。

2
这不是一个很Pythonic的方法,因为你的代码在items['itemCode']0False[]{}或任何其他求值为False的情况下会失败。在这种情况下,try/except更受欢迎,因为它实际上捕获了未找到该项的特定情况。使用if not itemCode可能会出现误报。 - Kirk Strauser
是的,非常抱歉,这是我的错误(我真的很累,试图快速回答)。当检查值是否为None(或不是)时,应始终使用is Noneis not None。我已经纠正了代码。 - cleg
但即使在新代码中,您也无法区分 'itemCode' not in itemsitems['itemcode'] is NoneNone 是一个完全有效的值来存储,而且 NoneKeyError 之间有很大的区别。不要道歉,我们都在努力一起解决这些问题。 :-) - Kirk Strauser
没错,你是对的。最好的方法是使用 in 检查子键。我仍然认为这在大多数情况下比捕获异常更好。但在许多情况下(包括这种情况),None 是不可接受的值,所以这将起作用。但是,你肯定需要了解这样做的风险。 - cleg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接