我们是否应该始终用try...except 块来包含我们编写的每个函数 ?我问这个是因为有时在我们引发的一个函数中Exception,调用这个函数的调用者没有异常
def caller():
stdout, stderr = callee(....)
def callee():
....
if stderr:
raise StandardError(....)
Run Code Online (Sandbox Code Playgroud)
然后我们的申请崩溃.在这个明显的情况下,我很想把被调用者和调用者包围起来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
Run Code Online (Sandbox Code Playgroud)
困扰我的真正的事情是:
如果有一个第三个函数调用addandremove()其中一个语句,我们是否还使用try..except块包围调用?如果第3个函数有3行,并且每个函数调用自己有一个try-except怎么办?我很抱歉建立这个.但这是我没有得到的那种问题.
顾名思义,例外情况是特殊情况 - 不应该发生的事情
..因为它们可能不应该发生,在大多数情况下,你可以忽略它们.这是一件好事.
除了特定的例外,有时您会这样做,例如,如果我这样做:
urllib2.urlopen("http://example.com")
Run Code Online (Sandbox Code Playgroud)
在这种情况下,期望"无法联系服务器"错误是合理的,因此您可能会这样做:
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
Run Code Online (Sandbox Code Playgroud)
然而,尝试捕获每一个可能的错误都是徒劳的 - 有无数的东西可能会出错.作为一个奇怪的例子,如果一个模块修改urllib2并移除urlopen属性会怎样- 没有理由期待这个NameError,并且没有理智的方法你可以处理这样的错误,因此你只是让异常传播
使用回溯退出代码是一件好事 - 它允许您轻松查看问题的来源,导致问题的原因(基于异常及其消息),并解决问题的原因,或处理异常正确的位置......
简而言之,只有在您可以对它们执行有用的操作时才处理异常.如果没有,尝试处理所有无数可能的错误只会使你的代码变得更加困难并且难以修复
在您提供的示例中,try/except块不执行任何操作 - 它们只是重新添加异常,因此它与更整洁的相同:
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
Run Code Online (Sandbox Code Playgroud)
关于我可能期望的唯一与异常处理相关的事情是处理如果找不到'hg'命令,则产生的异常不是特别描述性的.所以对于图书馆,我会做类似的事情:
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)
Run Code Online (Sandbox Code Playgroud)
这只是在更清晰的"CommandNotFound"中包含了可能令人困惑的"OSError"异常.
重读这个问题,我怀疑你可能误解了Python异常是如何工作的("和调用这个函数的调用者没有异常"位,所以希望澄清一下:
调用函数不需要知道可能从子函数引发的异常.您可以调用该cmd()函数并希望它正常工作.
假设您的代码在一个mystuff模块中,而其他人想要使用它,他们可能会这样做:
import mystuff
mystuff.addandremove("myfile.txt")
Run Code Online (Sandbox Code Playgroud)
或者,也许他们想要提供一个很好的错误消息,如果用户没有hg安装,则退出:
import mystuff
try:
mystuff.addandremove("myfile.txt")
except mystuff.CommandNotFound:
print "You don't appear to have the 'hg' command installed"
print "You can install it with by... etc..."
myprogram.quit("blahblahblah")
Run Code Online (Sandbox Code Playgroud)
try/ exceptclauses实际上只有在你知道如何处理引发的错误时才有用.参加以下计划:
while True:
n=raw_input("Input a number>")
try:
n=float(n)
break
except ValueError:
print ("That wasn't a number!") #Try again.
Run Code Online (Sandbox Code Playgroud)
但是,您可能具有以下功能:
def mult_2_numbers(x,y):
return x*y
Run Code Online (Sandbox Code Playgroud)
并且用户可能会尝试将其用作:
my_new_list=mult_2_numbers([7,3],[8,7])
Run Code Online (Sandbox Code Playgroud)
用户可以将其放在try/except块中,但之后my_new_list不会被定义,并且可能稍后会引发异常(可能是NameError).在这种情况下,你会使调试更难,因为回溯中的行号/信息指向一段不是真正问题的代码.