python高级之 —— 异常处理
一、异常
异常就是代码执行过程中出错的信号,异常有三部分:追踪信息,异常类型,异常的值
在python中,错误出发的异常通常长这样
错误分为两种:
1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)
#语法错误示范一 if #语法错误示范二 def test: pass #语法错误示范三 class Foo pass #语法错误示范四 print(haha # SyntaxError: invalid syntax
2.逻辑错误
#TypeError: int类型不可迭代 for i in 3: pass # TypeError: 'int' object is not iterable #ValueError num=input(">>: ") #输入hello int(num) # ValueError: invalid literal for int() with base 10: 'hello' #NameError aaa # NameError: name 'aaa' is not defined #IndexError l=['egon','aa'] l[3] # IndexError: list index out of range #KeyError dic={'name':'egon'} dic['age'] # KeyError: 'age' #AttributeError class Foo:pass Foo.x # AttributeError: type object 'Foo' has no attribute 'x' #ZeroDivisionError:无法完成计算 res1=1/0 res2=1+'str' # ZeroDivisionError: division by zero
在python中,不同异常可以用不同的类型去标识,一个异常标识一种错误。
常见的异常
# SyntaxError: 语法错误 g= # SyntaxError: invalid syntax # NameError:名字不存在 age # NameError: name 'age' is not defined # FileNotFoundError:路径错误 open("asa") # FileNotFoundError: [Errno 2] No such file or directory: 'asa' # ValueError:文件已关闭,无法继续读写 f = open("1.今日内容") f.close() f.read() # ValueError: I/O operation on closed file # io.UnsupportedOpration: 读写模式错误,不能写入数据 f = open("1.今日内容",mode="rt",encoding="utf-8") f.write("123") # io.UnsupportedOperation: not writable # ValueError:数据的值错误导致 int("abc") # ValueError: invalid literal for int() with base 10: 'abc' # IndentationError: 缩进错误 def func(): print(1) print(2) # IndentationError: unexpected indent # IndexError: 索引不存在 li = [] li[1] # IndexError: list index out of range # KeyError: key不存在 dic = {} dic["name"] # KeyError: 'name'
当异常发生时,解释器会打印异常的详细信息,并终止程序执行
排查错误的方法: 1.定位到错误发生的位置,查看追踪信息 I.自定义代码,且没有调用任何内置模块或方法 ,那么错误位置一定在最后一行 II.调用了其他模块的方法 内置模块:一定是调用时出错 第三方:有可能出错,按追踪信息点击排查 2.查看异常类型 (如IndexError) 3.查看异常的值 (如list index out of range)
异常一旦发生就会导致程序终止,这对于用户而言体验极差。所以我们需要有一种机制能够防止程序因为异常而终止
二、异常处理
之前讲到错误分为两类,同样异常可由发生时间不同分为两类:
- 语法检测异常
- 运行时异常(解析执行期间发生)
为保证程序的健壮性与容错性,我们需要对异常进行处理
若错误发生的条件时可预知的,我们需要用if进行处理(在错误发生前预防)
Age=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的 age=int(age) if age == Age: print('you got it') break
若不可预知,则用try...except(在错误发生之后处理)
try: 被检测的代码块(可能发出错误的代码) except 异常类型:(异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。except可以有多个,即多分支) try中一旦检测到异常,就执行这个位置的逻辑(代码)
1:把错误处理和真正的工作分开来
2:代码更易组织,更清晰,复杂的工作任务更容易实现
3:毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了
万能异常 Exception 类(可能会导致程序既不报错也不正常运行,无法定位错误位置) try: 被检测代码(可能发出错误) (可以通过给异常去别名来获取异常的对象,对象中包含了错误信息) except Exception: try中一旦检测到异常,就执行这个位置的逻辑(代码) 也可以先捕获能够明确的异常类型,最后捕获万能异常类型
try: 被检测的代码块(可能发出错误的代码) except 异常类型:(except可以有多个) try中一旦检测到异常,就执行这个位置的逻辑(代码) else :(当没有发生异常会执行else,其只能在except后)
finally:
try: 被检测的代码块(可能发出错误的代码) except 异常类型:(except可以有多个) try中一旦检测到异常,就执行这个位置的逻辑(代码) finally :(无论是否发生异常,最后都会执行finally中代码)
finally的使用场景 可以用finally来执行一些清理操作 类似__del__
import io try: print("start") f = open("1.今日内容","rt",encoding="utf-8") f.read() print("end") except FileNotFoundError: print("文件路径错误...") except io.UnsupportedOperation: print("文件不能被写入....") finally: f.close() print(f.closed)
1.如果能明确知道异常发生原因 就不要产生异常 使用if判断等方式
2.不知道异常发生的原因 但是知道异常的类型 那就明确捕获该类型的异常
3.不知道发生原因 也不知道 异常的类型 可以使用万能异常 但是一定要打印异常消息
主动发出异常:
try: raise TypeError('类型错误') except Exception as e: print(e) # 类型错误 # raise 关键字,后面跟任意Exception类型的子类
自定义异常:
class EgonException(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: raise EgonException('类型错误') except EgonException as e: print(e) --------------------------------------------------------- class LoginException(Exception): pass def login(): name = input("username:").strip() pwd = input("password:").strip() if name == "blex" and pwd == "123": print("登录成功!") else: raise LoginException("用户名或密码不正确....") login()
-- 该类有个input方法,调用该方法一定会得到一个合法的数字(非数字为不合法,越界为不合法) ---- 如果是非数字不合法,需要打印不合法消息,然后用户需要重新输入 -- 如输入'abc',不合法消息就为:invalid literal for int() with base 10: 'abc'----->ValueError ---- 如果是越界不合法,需要打印不合法消息,然后用户需要重新输入 -- 如输入'2147483648',不合法消息就为:ErrorMsg:2147483648 - 越界 提示: 1)该方法需要捕获并处理两次异常(内置异常ValueError,自定义异常SlopOverError) 2)该方法运用到递归方式处理更简单,如果用不到递归也可以 -- 该类有个verifySlopOver方法,可以判断传入的数字是否越界(非-2147483648 ~ 2147483647为越界) ---- 如果数字越界,会主动抛出自定义SlopOverError异常,并传入数字和异常消息 自定义异常SlopOverError类 -- 该类需要重写__init__方法 ---- 有num、msg两个参数,num是数字类型的数,msg是字符串类型的异常消息 -- 该类需要重写__msr__方法 ---- 通过num、msg两个属性格式化异常信息 自定义异常SlopOverError类 -- 该类需要重写__init__方法 ---- 有num、msg两个参数,num是数字类型的数,msg是字符串类型的异常消息 -- 该类需要重写__str__方法 ---- 通过num、msg两个属性格式化异常信息 class SlopOverError(Exception): def __init__(self,num,msg): self.num=num self.msg=msg def __str__(self): return "%s %s -- 越界"%(self.msg,self.num) class Integer: @staticmethod def input(): while True: num=input("-------->").strip() try: num=int(num) Integer.verifySlopOver(num) return num except ValueError as e: print(e) except SlopOverError as e: print(e) @staticmethod def verifySlopOver(num): if num<-2147483648 or num>2147483647: raise SlopOverError(num,"ErrorMsg:") res=Integer.input() print(res)