Python 除了在每个函数中,我们是否使用try?
除了块之外,我们是否应该总是用一个Python 除了在每个函数中,我们是否使用try?,python,exception,Python,Exception,除了块之外,我们是否应该总是用一个try…来封装我们编写的每个函数? 我这样问是因为有时在一个函数中我们会引发异常,而调用此函数的调用方没有异常 def caller(): stdout, stderr = callee(....) def callee(): .... if stderr: raise StandardError(....) 然后我们的应用程序崩溃了。在这种明显的情况下,我试图用try..except将被调用者和调用者括起来 但是我已经读
try…来封装我们编写的每个函数?
我这样问是因为有时在一个函数中我们会引发异常,而调用此函数的调用方没有异常
def caller():
stdout, stderr = callee(....)
def callee():
....
if stderr:
raise StandardError(....)
然后我们的应用程序崩溃了。在这种明显的情况下,我试图用try..except
将被调用者和调用者括起来
但是我已经读了很多Python代码,他们不会一直做这些try..block
真正困扰我的是:
如果有第三个函数在其中一个语句中调用addandremove()
,我们是否也会在调用的周围加上try..except块?如果第三个函数有3行,并且每个函数调用本身都有一个try-except,该怎么办?我很抱歉把这件事搞砸了。但这是我没有遇到的问题。您应该使用try-catch块,以便能够专门定位异常的源。你可以把这些块放在你想要的任何东西周围,但是除非它们产生某种有用的信息,否则就没有必要添加它们。试试看
/,除非
子句只有在你知道如何处理引发的错误时才真正有用。采取以下方案:
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块,但是我的新列表
将不会被定义,并且可能只是在稍后引发异常(可能是名称错误)。在这种情况下,您将更难调试,因为回溯中的行号/信息指向一段不是真正问题的代码;主要例外情况的作用包括(引自《辉煌之书》):
- 错误处理
- 事件通知
- 特殊案件处理
- 终止行动
- 异常控制流
当您知道将出现什么错误时,使用try/except进行调试。否则,您不必对每个函数都使用try/except 例外,顾名思义,是指特殊情况——不应该发生的事情
…因为它们可能不应该发生,在大多数情况下,你可以忽略它们。这是一件好事
有时您会执行以下操作,但特定的例外情况除外,例如,如果我执行以下操作:
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
import mystuff
mystuff.addandremove("myfile.txt")
然而,试图抓住每一个可能的错误是徒劳的——有无数的事情可能会出错。。作为一个奇怪的例子,如果一个模块修改了urllib2
并删除了urlopen
属性,那么会发生什么呢?没有合理的理由期待namererror
,也没有合理的方法可以处理这样的错误,因此您只能让异常传播
让您的代码带着回溯退出是一件好事-它使您能够轻松地看到问题的起因,以及导致问题的原因(基于异常及其消息),并修复问题的原因,或者在正确的位置处理异常
简言之,只有当您可以对异常做一些有用的事情时,才可以处理异常。否则,试图处理所有无数可能的错误只会使您的代码更混乱,更难修复
在您提供的示例中,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
与异常处理相关的唯一一件事是,如果找不到“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)
这只是在更清晰的“CommandNotFound”中封装了可能令人困惑的“OSError”异常
重读这个问题,我怀疑您可能误解了Python异常是如何工作的(“调用此函数的调用方没有异常”位,希望澄清一下:
调用方函数不需要了解可能从子函数引发的异常。您只需调用cmd()
函数,希望它能正常工作
假设您的代码位于mystuff
模块中,而其他人想要使用它,他们可能会这样做:
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
import mystuff
mystuff.addandremove("myfile.txt")
或者,如果用户没有安装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")
关于内省类型工具和“异常”处理,您的编码团队需要做出几个编程决策
使用异常处理的一个好地方是操作系统调用,例如文件操作。推理是,例如,一个文件的访问可能会受到限制,无法被客户端应用程序访问。该访问限制通常是操作系统管理任务,而不是Python应用程序函数。因此,在应用程序没有控制权
您可以将上一段中异常的应用范围进行更广泛的修改,即将异常用于团队代码无法控制的事情,例如所有“设备”或操作系统资源,如操作系统计时器、符号链接、网络连接等
另一种常见的使用情况是,当您使用一个库或包,该库或包被设计为通过大量异常,并且该包希望您捕获或编码这些异常。一些包被设计为抛出尽可能少的异常,并希望您根据返回值进行编码。那么您的异常应该很少
一些编码团队使用异常作为记录应用程序中“事件”的一种方式
我发现,在决定是否使用异常时,我要么通过不使用大量try/except来编程以最小化失败,要么让调用例程期望有效的返回值,要么期望无效的返回值