1.如何解决异常?
系统一开始已经内置了一些特定的应用场景;当我们写代码过程中,一旦触发了这个场景,系统内部就会自动的向外界抛出这个问题,也就是我们所谓的异常。程序被终止执行,软件崩溃。
预防:添加容错代码。
弊端:容错代码不属于我们主要的业务逻辑,如果容错代码过过多,会造成代码混乱,主业务不清晰。
解决:捕捉处理异常
方案1:
语法:
try:
可能出现异常的代码->(这里不管以后会抛出多少个异常,只会从上往下检测,检测到最后一个,就立即往下去匹配,不会多次检测。)
except 你要捕捉的异常类别 as(python2使用,)接收异常的形参。->(这一大块可以有多个重复,用于捕捉可能的其他异
对于这个异常的处理。 常,如果针对多个不同的异常有相同的处理方式,那 么可以将多个异常合并)
else
没有出现异常时做的处理。->(这一块必须放在except结束之后(可以省略))
finally:
不管有没有异常,都会执行的代码。->(这一块必须放在最后(可以省略))
注意:try语句没有捕获到异常,先执行try代码段后,在执行else,最后执行finally。如果捕获异常,首先执行except处理错误,然后执行finally。如果异常名称不确定,而又想捕捉,可以直接写Exception。
try:
1 / 0
except ZeroDivisionError as ze:
print("xxxx", ze)
except NameError as ne:
print("名称错误", ne)
else:
print(123)
finally:
print("最后行的内容,不管是否出现异常,都会执行的语句。")
# 异常的合并,针对不同的异常又想合并处理
try:
1 / 0
print(name)
# 将异常合并包装成一个元组
except (ZeroDivisionError, NameError) as e:
print("xxxx", e)
else:
print(123)
finally:
print("最后行的内容,不管是否出现异常,都会执行的语句。")
# 当不知道准确的异常时,可以直接使用Exception
try:
1 / 0
print(name)
# 将异常合并包装成一个元组
except Exception as e:
print("xxxx", e)
else:
print(123)
finally:
print("最后行的内容,不管是否出现异常,都会执行的语句。")
方案2:
作用:适用于执行某一段代码A之前,进行预处理,执行代码A结束后,执行清理操作。不管出现了什么异常,最终都要执行一些清理操作。
语法:
with context_expression [as target(s)]
with-body
语法图解:
示例:
文件读取操作正常步骤:打开文件:f = open("xxx.txt")
读取文件:f.readlines() -> 如果这一行代码抛出异常,就会影响后续“文件关闭”操作的执行。
关闭文件:f.close()
于是,我们想保证,不管读取文件操作有没有异常,都要关闭文件。(try:
打开文件
读取文件
finally:
关闭文件
)
但是以上写法过于繁琐,于是有了这个方案。
(with open(file) as f:
读取文件
)
上述代码的问题:代码如果出现异常,并没有处理掉。
try: f = open("xxx.jpg", "r") f.readlines() except Exception as e: print(e) finally: print("xxxxxx") f.close() # with open("xxx.jpg", "r") as f: # f.readlines()
补充:
自定义上下文管理器:
exc_typ:异常的类型, exc_val:异常的值 exc_tb:异常的追踪信息
class Test: def __enter__(self): print("enter") return self # exc_typ:异常的类型, exc_val:异常的值 exc_tb:异常的追踪信息 def __exit__(self, exc_type, exc_val, exc_tb): print(self, exc_type, exc_val, exc_tb) # 手动的追踪出错的位置 import traceback print(traceback.extract_tb(exc_tb)) print("exit") # 当这里返回True的时候,这些异常会自动的传递给退出方法。内部消化,不会再往外传了。如果返回False或者none,则外面 # 依然会接收到异常。造成代码崩溃 return True with Test() as x: # print("body", x) 1 / 0
contextlib模块:
@contextlib.contextmanager -> 使用装饰器,让一个生成器编程一个“上下文管理器”
@contextlib.contextmanager def ze(): try: yield except Exception as g: print("Error", g) x = 1 y = 0 with ze(): x / y a = 1 b = 0 with ze(): a / b # try: # a / b # except Exception as f: # print("error", f) # with test() as x: # print(3, x)
contextlib.closing:这个函数让一个拥有close方法,但是不是上下文管理器的对象,变成“上下文管理器”
import contextlib class Test: def t(self): print("tttttt") def close(self): print("资源释放") # def __enter__(self): # return self # def __exit__(self, exc_type, exc_val, exc_tb): # self.close() with contextlib.closing(Test()) as t_obj: t_obj.t()
contextlib.nested:python2.7之前,完成多个上下文管理器的嵌套。
# 多上下文管理器嵌套 # with open("xxx.jpg", "rb") as from_file: # with open("xxx2.jpg", "wb") as to_file: # from_context = from_file.read() # to_file.write(from_context) # python3.x版本后写法 # with open("xxx.jpg", "rb") as from_file, open("xxx2.jpg", "wb") as to_file: # from_context = from_file.read() # to_file.write(from_context) # python2.x版本后写法 import contextlib with contextlib.nested(open("xxx.jpg", "rb"), open("xxx2.jpg", "wb")) as (from_file, to_file): from_context = from_file.read() to_file.write(from_context)
基本小案例:
import contextlib # 通过导入contextlib,利用contextlib.contextmanager生成一个上下文管理器。yield上面是__enter__。yield下面是__exit__。 @contextlib.contextmanager def test(): print(1) # yield 后面直接写值,就是下面x的值。 yield "xxx" print(2) with test() as x: print(3, x)