当前位置: 首页 > 后端技术 > Python

Python错误与异常

时间:2023-03-26 01:20:18 Python

错误与异常在编写代码时,无论是什么原因,你都可能在运行阶段看到过一些错误信息。在这些消息中(至少)有两种可区分的错误类型:语法错误和异常。语法错误语法错误也称为解析错误,这可能是学习编码时最常遇到的错误:>>>whileTrueprint('HelloWorld')File"",line1whileTrueprint('HelloWorld')^SyntaxError:invalidsyntax当发生错误时,解释器会输出发生语法错误的行,同时还会显示^符号来标记检测到的错误。符号的位置标记了错误发生的位置(或至少是检测到错误的位置)。在此示例中,print()函数被检测为错误,因为前面的条件语句缺少冒号(:)。错误信息中会有行号和文件名,可以方便出错时在相应位置查看。异常有时候,检查写好的代码发现没有语法错误,但是执行起来还是会报错。在执行时检测到的此类错误称为异常。大多数异常不会被程序处理,并且会显示以下错误消息:>>>10/0Traceback(mostrecentcalllast):File"",line1,inZeroDivisionError:divisionbyzero>>>x+4Traceback(最近调用最后):文件“”,第1行,在NameError:name'x'isnotdefined>>>1+'1'Traceback(最近调用last):File"",line1,inTypeError:unsupportedoperandtype(s)for+:'int'and'str'如上例所示,错误消息的最后一行将告诉我们程序遇到什么类型的错误。在上面的例子中,发生的异常类型有:ZeroDivisionError、NameError和TypeError。类型后半部分的信息表示根据异常类型及其原因提供详细信息。异常处理python内置的try...except...错误处理机制。看一下try...except...机制的例子:try:r=10/0print('r=',r)exceptZeroDivisionErrorase:print('except:',e)print('END')程序运行结果如下:except:除以零END这里描述一下try语句的工作原理:首先,执行try子句(即try和except关键字之间的语句).如果此时没有异常发生,则跳过except子句,完成try语句的执行。如果try子句执行过程中发生异常,则跳过该子句的其余部分(例如本例中的10/0将产生异常,后续的print('r=',r)语句将不实施)。此时如果异常类型与except关键字后的异常类型相匹配,就会执行except子句。最后继续执行整个try语句之后的代码(比如本例中的print('END'))。如果异常与except关键字后指定的异常不匹配,则传递给外部;如果没有找到处理程序,则认为是未处理的异常,将停止执行并显示上述错误信息。本例中try子句中的10/0是异常的,所以后面的print()子句的内容没有输出。然后,匹配except之后的异常,所以输出except:divisionbyzero的异常信息,最后输出整个try语句后的print('END')语句。这就是try...except...捕获异常和处理异常的一般原理。在try...except语句之后还有一个可选的else子句,使用时放在except子句之后。当try子句没有异常发生时执行。对前面的例子进行一些修改,例如:try:r=10/1print('r=',r)exceptZeroDivisionErrorase:print('except:',e)else:print('Noerror!')print('END')的最终输出:r=10.0没有错误!END抛出异常raise语句允许编码器强制抛出指定的异常。例如:>>>raiseNameError('Anerroroccurredhere')Traceback(mostrecentcalllast):File"",line1,inNameError:Anerroroccurredhereraise唯一的参数是抛出例外。该参数必须是异常实例或异常类(派生自Exception的类)。如果你打算判断异常是否已经发生,但不打算处理它,你可以使用简单形式的raise语句来重新引发异常。例如:>>>try:...raiseNameError('Anerroroccurredhere.')...exceptNameError:...print('Anexceptionflushby!')...raise...Anexception飞过!回溯(最近调用最后):文件“”,第2行,在NameError:此处发生错误。自定义异常类程序可以通过创建新的异常类来命名自己的异常。自定义异常类通常直接或间接派生自异常类。classError(Exception):'''基类'''passclassInputError(Error):'''输入表达式错误时抛出异常属性:表达式--输入表达式消息--异常输出信息'''def__init__(self,expression,message):self.expression=expressionself.message=messageclassTransitionError(Error):'''不允许状态转换时抛出异常属性:previous--转换前的状态next--转换后的新状态statemessage--statetransitionisnotallowed'''def__init__(self,previous,next,message):self.previous=previousself.next=nextself.message=message通常,自定义异常名称都以Error结尾,类似于标准异常的命名。定义清理操作try语句还有一个可选的finally子句。用于定义必须在所有情况下执行的清理操作。例如:>>>defdivide(a,b):...try:...res=a/b...exceptZeroDivisionError:...print('divisionbyzero!')...else:...print('res=',res)...finally:...print('执行finally子句')...>>>divide(10,1)res=10.0executingfinally子句>>>divide(10,0)除以零!executingfinallyclause>>>divide('10','1')executingfinallyclauseTraceback(mostrecentcalllast):File"",line1,in文件"",line3,在divideTypeError:unsupportedoperandtype(s)for/:'str'and'str'这里可以看到,不管是什么情况,finally最终都会被执行。在最后一个例子中,由于两个字符串的划分不是由except子句处理的,所以这里执行finally子句后会抛出TypeError异常。finally子句对于释放外部资源(如读写文件或网络连接)很有用,无论这些资源是否被成功使用。我们来看一段预定义清理操作的示例代码:forlineinopen('file.txt'):print(line,end='')其实这段代码是有问题的。这部分代码执行后,会在不确定的时间段内保持文件对象打开。这对简单的脚本可能影响不大,但如果程序足够大,这就会成为问题。Python提供了一个with语句,允许支持上下文管理协议的对象确保它们被及时正确地清理:withopen('file.txt')asf:forlineinf:print(line,end='')在这里,文件f会一直关闭,以免浪费资源。参考来源《8.错误与异常》.docs.python.org.Retrieved24February2020.《Exceptionhierarchy》.docs.python.org.Retrieved2020.2.25.以上是关于程序错误和异常的相关内容。欢迎关注微信公众号《书所集录》