我们是否应该始终用try...except
块包含我们编写的每个函数?
我问这个是因为有时在一个函数中我们引发Exception
,并且调用此函数的调用者没有异常
def caller():
stdout, stderr = callee(....)
def callee():
....
if stderr:
raise StandardError(....)
然后我们的应用程序崩溃了。在这个明显的情况下,我很想用try..except
包围被调用者和来电者。
但是我已经阅读了很多Python代码,而且他们并不是一直都在执行try..block
。
def cmd(cmdl):
try:
pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
except Exception, e:
raise e
stdout, stderr = pid.communicate()
if pid.returncode != 0:
raise StandardError(stderr)
return (stdout, stderr)
def addandremove(*args,**kwargs):
target = kwargs.get('local', os.getcwd())
f = kwargs.get('file', None)
vcs = kwargs.get('vcs', 'hg')
if vcs is "hg":
try:
stdout, stderr = cmd(['hg', 'addremove', '--similarity 95'])
except StandardError, e:
// do some recovery
except Exception, e:
// do something meaningful
return True
困扰我的真实事实是:
如果在其中一个语句中有第三个函数调用addandremove()
,我们是否还使用try..except块包围调用?如果第3个函数有3行,并且每个函数调用自己有一个try-except怎么办?我很抱歉建立这个。但这是我没有得到的那种问题。
答案 0 :(得分:8)
顾名思义,例外情况是特殊情况 - 不应该发生的事情
..因为它们可能不应该发生,在大多数情况下,你可以忽略它们。这是一件好事。
有些时候你做除了特定的例外,例如我这样做:
urllib2.urlopen("http://example.com")
在这种情况下,期望“无法联系服务器”错误是合理的,因此您可能会这样做:
try:
urllib2.urlopen("http://example.com")
except urllib2.URLError:
# code to handle the error, maybe retry the server,
# report the error in a helpful way to the user etc
然而,尝试捕捉每一个可能的错误都是徒劳的 - 有无数的事情可能会出错......作为一个奇怪的例子,如果模块修改urllib2
并删除{{1属性 - 没有理由期望urlopen
,并且没有理智的方法可以处理这样的错误,因此你只是让异常传播
使用回溯退出代码是一件好事 - 它允许您轻松查看问题的来源,导致问题的原因(基于异常及其消息),并解决问题的原因或处理问题正确位置的例外...
简而言之,只有你可以对它们做一些有用的事情时才处理异常。如果没有,尝试处理所有无数可能的错误只会使你的代码变得更加困难并且难以修复
在您提供的示例中,try / except块不执行任何操作 - 它们只是重新添加异常,因此它与更整洁的相同:
NameError
关于我可能期望的唯一与异常处理相关的事情是处理如果找不到'hg'命令,结果异常不是特别描述性的。所以对于一个图书馆,我会做类似的事情:
def cmd(cmdl):
pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
stdout, stderr = pid.communicate()
if pid.returncode != 0:
raise StandardError(stderr)
return (stdout, stderr)
# Note: Better to use actual args instead of * and **,
# gives better error handling and docs from help()
def addandremove(fname, local = None, vcs = 'hg'):
if target is None:
target = os.getcwd()
if vcs is "hg":
stdout, stderr = cmd(['hg', 'addremove', '--similarity 95'])
return True
这只是在更清晰的“CommandNotFound”中包含可能令人困惑的“OSError”异常。
重读这个问题,我怀疑你可能误解了Python异常是如何工作的(“调用此函数的调用者没有异常”位,所以希望澄清:
调用函数不需要知道可能从子函数引发的异常。你可以调用class CommandNotFound(Exception): pass
def cmd(cmdl):
try:
pid = Popen(cmdl, stdout=PIPE, stderr=PIPE)
except OSError, e:
if e.errno == 2:
raise CommandNotFound("The command %r could not be found" % cmdl)
else:
# Unexpected error-number in OSError,
# so a bare "raise" statement will reraise the error
raise
stdout, stderr = pid.communicate()
if pid.returncode != 0:
raise StandardError(stderr)
return (stdout, stderr)
函数,希望它能正常工作。
假设您的代码位于cmd()
模块中,而其他人想要使用它,他们可能会这样做:
mystuff
或者,也许他们想要提供一个很好的错误消息,如果用户没有安装import mystuff
mystuff.addandremove("myfile.txt")
则退出:
hg
答案 1 :(得分:6)
您应该使用try catch块,以便您可以专门定位异常的来源。您可以将这些块放在您想要的任何地方,但除非它们产生某种有用的信息,否则无需添加它们。
答案 2 :(得分:6)
try
/ except
子句才真正有用。采取以下计划:
while True:
n=raw_input("Input a number>")
try:
n=float(n)
break
except ValueError:
print ("That wasn't a number!") #Try again.
但是,您可能具有以下功能:
def mult_2_numbers(x,y):
return x*y
用户可以尝试将其用作:
my_new_list=mult_2_numbers([7,3],[8,7])
用户可以将其放在try / except块中,但之后my_new_list
将不会被定义,并且可能稍后会引发异常(可能是NameError)。在这种情况下,你会更难调试,因为回溯中的行号/信息指向一段不是真正问题的代码。
答案 3 :(得分:1)
编码团队有一些关于内省类型工具和“异常”处理的编程决策。
使用异常处理的一个好地方是操作系统调用,例如文件操作。例如,推理是一个文件可能限制其访问被客户端应用程序访问。访问限制通常是OS-admin任务,而不是Python应用程序功能。因此,在应用程序无法控制的情况下,异常将是一个很好的用途。
您可以将前一段的异常应用变更为更广泛,从使用例外来控制您的团队代码之外的事物,到诸如所有“设备”或OS资源(如OS定时器),符号链接之类的东西,网络连接等
另一个常见用例是当您使用通过大量异常设计的库或包时,该包期望您捕获或编写该包。有些软件包旨在尽可能少地抛出异常,并期望您根据返回值进行编码。那么你的例外应该很少见。
一些编码团队使用异常作为记录应用程序中“事件”的边缘情况的方法。
我发现在决定是否使用异常时,我要编程以通过没有大量的try / except来最小化失败,并且调用例程期望有效的返回值或期望无效的返回值。或者我为失败而编程。也就是说,我通过函数编程预期的失败,我使用了很多try / except块。考虑编程“预期”失败,如使用TCP;数据包不是为了到达那里,甚至是按顺序,但是通过使用发送/读取重试等来处理TCP的异常处理。
我个人使用try-except块围绕最小的块大小,通常是一行代码。
答案 4 :(得分:0)
取决于你;主要的例外'角色涉及(引自this精彩的书):
答案 5 :(得分:0)
当您知道错误是什么时,请使用try / except进行调试。否则,您不必对每个函数使用try / except。