当前位置: 首页 > Linux

[Python]-6-Decisionloopandexceptionhandling

时间:2023-04-07 01:59:28 Linux

Introduction本文介绍python中的流程控制和异常处理。文章目录0×1。使用if来做出0×2的决定。循环0×3。迭代器0×4。异常捕获和处理0×1。使用if做判断python的if语句和其他编程语言最大的区别说明每一个分支后面需要加一个描述编号,请看下面的例子:#!/usr/bin/envpython3#coding=utf-8try:a=input("请输入整数0:")ifint(a)==0:print("www.qingsword.com")elifint(a)>0:print("a大于0")else:print("aislessthan0")exceptValueErroraserr:print(err)#这是一个简单的小程序。try...except语句用于捕获代码运行时的异常。也就是说,如果try中包含的语句执行失败,就会跳转到except分支去匹配异常类型。本例中只提供了一种错误类型,即ValueError异常。当用户输入非数字时,int(a)转换函数会抛出这个异常。这个异常会被print(err)语句打印到屏幕上,err是一个自定义的变量名,相当于对ValueError异常信息的引用。#input()函数会暂停程序,等待用户输入,根据用户输入执行if判断。如果等于0,则打印出网站URL;如果大于0则匹配elif分支,如果小于0则匹配else分支,if语句块可以包含多个elif分支来匹配不同的情况,当所有条件都不匹配时匹配else分支,if语句执行每一个Branches,只要其中一个分支匹配成功,执行完该分支下的语句后,会立即跳出if语句块,不再匹配后面的分支(即使后面的分支可以匹配则不执行)0×2.python中有两种循环while和for两种循环,请看下面的例子;while循环示例:#!/usr/bin/envpython3#coding=utf-8#导入pythonimportrandom自带的随机数生成器#while后面的条件为True会一直循环whileTrue:#随机生成一个数从1to100i=random.randint(1,100)#如果数字小于50,continue语句会让流程跳转到while从头继续循环ifi<50:continue#如果大于等于50,打印出这个数,break语句会终止跳出循环print(i)break#anotherwhile循环实例,num会从5减到0当num大于0为假时,终止循环num=5whilenum>0:print(num)num-=1forloopexample:#!/usr/bin/envpython3#coding=utf-8#从元组中依次读取Elementprintingforiin("a","b","c"):print(i)#range()方法接受三个参数,分别是range(startingnumber,endingnumber,tolerance),当只设置一个参数时,起始编号默认为0,tolerance默认为1。在这个例子中,i会从0读到4,但不会包括4,所以打印出来的数字应该是0,1,2,3foriinrange(4):print(i)#Setthestartnumberto1,endnumberto4,printout1,2,3foriinrange(1,4):print(i)#toleranceis2,printout0从11到11的所有偶数foriinrange(0,11,2):print(i)#for循环依次读取list数据的实例,len()计算a的长度为3,range(3)等价于(0,1,2)、print函数打印出range(len(a))中列表中每个索引位置对应的元素a=["www.qingsword.com","Qingsword","qingsword"]fori:print(str(i)+"~"+a[i])#除了可以用上面的方法打印出每个元素对应的索引外,python还提供了一个枚举函数,可以直接将列表分解成如下形式索引对应的元素,例如#!/usr/bin/envpython#coding=utf-8L=["a","b","c","d"]print(tuple(enumerate(L)))fori,ainenumerate(L):print(i,a)#programoutput((0,'a'),(1,'b'),(2,'c'),(3,'d'))0a1b2c3dfor迭代字典实例:#!/usr/bin/envpython#coding=utf-8d={"one":1,"two":2,"three":3,"four":4}#默认只遍历字典的key,等价to"foraind.keys()"foraind:print(a)#如果要遍历值,可以使用如下方法foraind.values():print(a)#If想同时遍历key值,可以使用Beforein,在d.items()中对a,b使用两个变量:print(a,b)#程序输出onetwofourthree1243one1two2four4three3#用于携带多个变量不仅可以用在字典中,也可以用在多维列表或元组中,例如#!/usr/bin/envpython#coding=utf-8L=[[1,11,111],[2,22,222],[3,33,333]]forx,y,zinL:print(x,y,z)#programoutput111111222222333333foriterationstringexample:#!/usr/bin/envpython#coding=utf-8s0="www.qingsword.com"s1=""forains0:s1+=aprint(s1)#程序使用for循环每次读取s0中的一个字符添加到s1中,完成从s0的复制tos1Ps:while循环中的continue和break语句for循环同理0×3。迭代器列表、字典、元组、字符串都是可迭代类型,那么如何判断哪种数据类型是可迭代的呢?可以使用collections模块的Iterable类型来判断,例如:#coding=utf-8fromcollectionsimportIterableprint(isinstance(123,Iterable))print(isinstance("www.qingsword.com",Iterable))print(isinstance(["www.qingsword.com","qingsword"],Iterable))#程序输出,从输出可以看出,整数123无法迭代,所以返回False,下面的字符串和列表是可迭代类型FALSETRUETRUE,可以直接作用于for循环的对象统称为可迭代对象(Iterable),而生成器(列表生成器和函数生成器)不仅可以作用于for循环,还可以被for循环不断调用next()函数并返回下一个值,直到最后抛出StopIteration错误。能被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator);你可以使用isinstance()来判断一个对象是否是一个Iterator对象:#!/usr/bin/envpython#coding=utf-8fromcollectionsimportIteratorprint(isinstance([],Iterator))print(isinstance("www.qingsword.com",Iterator))print(isinstance({},Iterator))print(isinstance((xforxinrange(3)),Iterator))#从下面的输出可以看出,虽然两者都列出字符串和字典都是可迭代对象(Iterable),它们不是迭代器(Iterator),只有最后一个列表生成器是可迭代的(Itisalistgenerator而不是listgenerator,注意两个括号的区别,一个是squareFALSEFALSEFALSETRUE在Python中,一个迭代器保存了一组算法,这组算法可以计算一个数据流,可以是无穷大(比如实数的集合)或有限的数据流。迭代器对象可以被next()函数调用并继续返回下一个数据,直到没有更多的数据。当抛出StopIteration错误时,迭代器对象会在我们访问这个迭代器时计算数据流中的下一个值。Python允许使用iter()函数将可迭代对象转换为迭代器,例如:#!/usr/bin/envpython#coding=utf-8fromcollectionsimportIteratorprint(isinstance(iter([]),Iterator))print(isinstance(iter("www.qingsword.com"),Iterator))#程序输出TRUETRUEfor循环和迭代器的比较如下:#!/usr/bin/envpython#coding=utf-8L1=[1,2,3]L2=iter(L1)#for循环迭代forainL1:print(a)#usenext()读取迭代器L2中的值(也可以使用for循环)whileTrue:try:print(next(L2))exceptStopIterationaserr:break从这个例子可以看出,Python的for循环和调用next()函数访问迭代器本质上是一样的。0×4。异常捕获和处理关于异常处理的语句在if中已经简单演示过了。try语句块和if一样,可以包含多个except分支用于捕获异常。可以在try结束时添加else分支。当没有捕获到异常时,就会运行该分支下的内容。可能有朋友会问:“我怎么知道异常的名称是什么?什么时候会发生异常?”我们在使用解释器运行程序的时候,总会遇到一些错误。当发生错误时,解释器将返回异常消息,其中包含异常的名称。我们只需要记录这些名字,然后用except来捕获即可。请看下面的例子:#!/usr/bin/envpython3#coding=utf-8d={1:"banana",2:"apple",3:"orange",4:"durian"}try:i=input("请输入你需要的水果编号(1-4):")i=int(i)ifi==1:print(d[i])elifint(i)==2:print(d[i])elifint(i)==3:print(d[i])elifint(i)==4:print(d[i])else:print(d[i])除了ValueErroraserr:print(err)exceptKeyErroraserr:passelse:print("Uncaughtexception")finally:print("End")#异常处理语句块可以包含多个excepts来捕获不同的异常,当不需要处理捕获到的异常时,可以在分支Enterpass,表示什么都不做。try语句块的末尾后面可以跟一个else分支。这个分支会在没有捕获到异常的情况下执行,但是一般不需要加这个分支。同时还可以加一个finally分支,不管有没有捕获到异常,都会执行这个分支。当程序执行过程中遇到异常时,如果加入异常处理语句,将直接跳转到异常分支进行处理,而不是继续执行后面的语句。如果没有异常处理如果能匹配到,程序会因为出错直接终止并打印异常信息(当i=int(i)时出现此异常,因为要转换的字符不是数字)输入你需要的水果编号(1-4):ainvalidliteralforint()withbase10:'a'#当输入不在1-4范围内的数字时,会触发KeyError异常。此异常发生在if块的else分支下的print(d[i])语句中。如果我输入6,d[6]在字典中根本找不到对应的key,所以会抛出“keyerror”,但是在这个分支下使用pass,会让程序静默处理,不会产生任何输出在屏幕上#When程序没有异常时,输出如下。输入你需要的水果编号(1-4):1banana没有捕获到异常End除了使用try捕获异常,还可以使用raise主动抛出异常,例如:#!/usr/bin/envpython3#coding=utf-8#创建绝对值转换函数defmy_abs(x):"""绝对值转换函数,如果输入不是整数或浮点数,使用raise关键字抛出TypeError异常,isinstance()函数接收两个参数,第一个参数是要判断的传入值,第二个参数是一个判断范围,本例判断x是整型还是浮点型"""ifnotisinstance(x,(int,float)):raiseTypeError("Badoperandtype.")elifx>=0:returnxelse:return-xprint(my_abs(-123))print(my_abs(23))print(my_abs(-3.14))#Programoutput123233.14#如果传入错误的值,会得到TypeErrorprint(my_abs("www.qingsword.com"))TypeError:Badoperandtype。有时我们捕获了一种错误,但又想抛出另一种类型的错误(虽然这种情况很少见),也可以使用raise关键字,例如:#!/usr/bin/envpython3#coding=utf-8defA(x=233):returnx/0#会报被除数不能为0的错误try:A()exceptZeroDivisionErroraserr:#捕捉到这个错误后,自定义抛出一个TypeError错误raiseTypeError("一般情况下,不要抛出完全不同类型的错误")以上抛出完全不同类型的错误是不推荐的,除非你知道你在做什么,抛出错误的正确方法如下:#!/usr/bin/envpython3#coding=utf-8defA(x=233):try:returnx/0exceptZeroDivisionErroraserr:print("被除数不能为0")raise#如果没有参数,则原样抛出当前错误。A()让我们看一个错误实例。Python允许使用try来捕获错误,但是如果不使用try语句,错误会从源头逐层返回,直到被python解释器捕获,比如下面的程序:#!/usr/bin/envpython3#coding=utf-8defA(x):returnx/0#错误的来源,0不能是被除数defB(x):returnA(x)*2defC():B(0)#当我们执行C()时,程序会报错C()print("End")#这句话没有执行,报错后程序终止#erroroutputFile"test2.py",line10、inC()#首先判断错误是这条语句引起的File"test2.py",line8,inCB(0)#但这个错误是因为C的B(0)statementFile"test2.py",line6,inBreturnA(x)*2#错误追溯到B中的return语句File"test2.py",line4,inAreturnx/0#Finally追溯A#中的return语句,打印出错误类型为ZeroDivisionError,被除数不能为0builtins.ZeroDivisionError:divisionbyzero我们注意到上面的程序是在debug之后直接终止的,但是在实际情况中我们可能需要记录并打印出这些错误信息,但仍然让程序继续运行直到结束,可以使用日志Logging模块logging完成这些操作,修改上面程序如下:#!/usr/bin/envpython3#coding=utf-8importlogging#引入logmoduledefA(x):returnx/0defB(x):returnA(x)*2defC():try:B(0)exceptExceptionaserr:logging.exception(err)#记录并打印捕获的错误C()print("end")#将logging.exception写入inexcept可以记录并打印出错误日志。输出这些错误日志信息后,程序会继续执行,最后打印出end(logging模块比print更详细的记录了错误的调用步骤,方便我们理解错误的根源在哪里,如果只是print(err),它只会打印被零除),下面是程序输出ERROR:root:divisionbyzeroTraceback(mostrecentcalllast):#errortrackinginformationFile"test2.py",line10,inCB(0)File"test2.py",line7,inBreturnA(x)*2File"test2.py",line5,inAreturnx/0ZeroDivisionError:divisionbyzeroend#programerror然后继续执行直到结束。您可能已经注意到,我们捕获的不同错误都有错误名称。这些名称在Python中是分层设计的(错误实际上是类,所有错误类型都继承自BaseException)。不同的错误是针对它们的父类和子类,父类的捕获优先级高于子类,也就是说如果我们在except中设置一个父类名,它会捕获所有的子类错误,而写另外一个except捕获它的子类是没有意义的,永远不会被执行。下面的列表列出了所有的错误类,缩进的是子类。通过这个列表不难看出为什么在上面的例子中通过CatchingException错误可以捕获到ZeroDivisionError错误,因为ZeroDivisionError是Exception的子类:BaseException+--SystemExit+--KeyboardInterrupt+--GeneratorExit+--Exception+--StopIteration+--StopAsyncIteration+--ArithmeticError|+--FloatingPointError|+--溢出错误|+--ZeroDivisionError+--AssertionError+--AttributeError+--BufferError+--EOFError+--ImportError+--LookupError|+--索引错误|+--KeyError+--MemoryError+--NameError|+--UnboundLocalError+--OSError|+--BlockingIOError|+--ChildProcessError|+--连接错误||+--BrokenPipeError||+--ConnectionAbortedError||+--ConnectionRefusedError||+--ConnectionResetError|+--FileExistsError|+--FileNotFoundError|+--中断错误|+--IsADirectoryError|+--NotADirectoryError|+--权限错误|+--ProcessLookupError|+--TimeoutError+--引用错误+--运行时错误|+--NotImplementedError|+--递归错误+--语法错误|+--缩进错误|+--TabError+--SystemError+--TypeError+--ValueError|+--UnicodeError|+--UnicodeDecodeError|+--UnicodeEncodeError|+-unicodetranslateError+-警告+-弃用warning+-pendendDeprecationWarning+-runtime-warning+-SyntaxWarning+-userWarning+-UserWarning+-FutureWarning+-ImportWarning+-importWarning+-UnicodeWarning+-unicodeWarning+-