python-异常-异常处理-自定义异常-断言

一、异常

  1. 什么是异常:指的是与正常情况不同,在程序中,程序的正常执行过程按照代码顺序 一行一行很执行,直到所有代码都执行完, 如果在执行过程中出现了错误,导致代码无法执行完毕,就称之为异常。异常其实就是代码执行过程中出错了
  2. 常见的异常类型:当异常发生时,解释器会打印异常详细信息并且终止程序的执行
  3. 如何排查排查错误:
    1. 定位到错误发生的位置,查看追踪信息,如果你的代码都是自己写的,没有调用任何内置模块或方法,那么错误发生位置一定在最后一行。如果你的代码调用其他模块的方法,是系统内置的模块,例如抛出位置object.py,不用去查看object类,它几乎不可能出错,一定是你自己代码在调用时出了错误。别人写的模块是有可能出错的,所以你可以按照追踪信息点击去看看绝招:如果有很多追踪信息,找最后一行是你自己写代码的位置
    2. 查看异常类型 例如:IndexError
    3. 查看异常的值 例如:list index out of range
    4. 如果没有任何异常信息,但是程序就是不对,可以使用排除法
  4. 异常的三个组成部分:
    1. 追踪信息
    2. 异常类型
    3. 异常的值
  5. 为什么使用异常处理:异常一旦发生就会导致程序终止,这对于用户而言体验极差,所以我们需要有一种机制能够防止程序因为异常而终止
#语法错误
a =
SyntaxError: invalid syntax   

#名字不存在
age
NameError: name 'age' is not defined

#路径错误
open("asasasas")
FileNotFoundError: [Errno 2] No such file or directory: 'asasasas'  

#文件已经关闭,你还要去读写
f = open("a.txt")
f.close()
f.read()
ValueError: I/O operation on closed file.
    
#不能写入数据,读写模式错误导致
f = open("a.txt",mode="rt",encoding="utf-8")
f.write("123")
io.UnsupportedOperation: not writable 

#数据的值错误导致
int("abc")
ValueError: invalid literal for int() with base 10: 'abc' 

#缩进错误
def func():
 print(1)
  print(2)
IndentationError: unexpected indent

#索引不存在
li = []
li[1]
IndexError: list index out of range
 
#key不存在
dic = {}
dic["name"]
KeyError: 'name'   

二、异常的处理

  1. 异常可以由发生的时间不同分为两类:

    1. 语法检测异常:解释器在执行代码前会先检测语法,检测通过才会开始执行,如果这个阶段发生了异常,代码一行都不会执行
    2. 运行时异常:已经通过了语法检测,在解析执行期间发生的异常
  2. 完整的书写顺序:

    try
    except
    else
    finally

  3. 正确使用异常处理:

    1. 如果能明确知道异常发生原因,就不要产生异常,使用if判断等方式
    2. 不知道异常发生的原因,但是知道异常的类型,那就明确捕获该类型的异常
    3. 不知道发生原因,也不知道异常的类型,可以使用万能异常,但是一定要打印异常消息

语法1 except

try:
    #把可能发出错误的代码放到try中
    print("start")
    a = int("abc")
    print("over")

except ValueError:
    #当try中真的发生了错误,就会执行except中的代码,在这里可以做一些补救措施
    print("发生了 ValueError 异常")

print("over")

语法2 except可以有多个

li = []
try:
    print("start")
    a = int("abc")
    li[1]
    print("over")

except ValueError:
    print("发生了 ValueError 异常")
except IndexError:
    print("发生了 IndexError 索引不正确")
print("over")

语法3 万能异常 Exception类

#万能异常Exception类,尽量少用,可能会导致程序既不报错,也不正常运行,无法定位错误位置
try:
    print("start")
    10 / 0
    dic = {}
    dic["name"]
    print("over")

except Exception:
    print("可能是任何类型的错误 反正是发生错误了")
print("over")

语法4 万能异常 Exception类

#万能异常Exception类,建议输出异常的值
try:
    print("start")
    10 / 0
    dic = {}
    dic["name"]
    print("over")

# 可以通过给异常取别名,来获取异常的对象,对象中包含了错误信息
except Exception as e:
    print("可能是任何类型的错误 反正是发生错误了")
    print(e)
    print(type(e))
print("over")

语法5 先捕获能够明确的异常类型,最后捕获万能异常类型

扫描二维码关注公众号,回复: 4940472 查看本文章
try:
     # 把可能发出错误的代码放到try中
    print("start")
    # a = int("abc")
    # li[1]
    10 / 0
    dic = {}
    dic["name"]
    print("over")
except ValueError:
    print("值不对.....")
except ZeroDivisionError:
    print("除数不能为0")
except Exception as e:
    print("可能是任何类型的错误 反正是发生错误了")
    print(e)
    print(type(e))

print("over")

语法6 try except else

try:
    print("start")
    # a = int("abc")
    # li[1]
    # 10 / 0
    dic = {}
    # dic["name"]
    print("over")
except ValueError:
    print("值不对.....")
except ZeroDivisionError:
    print("除数不能为0")
except Exception as e:
    print("可能是任何类型的错误 反正是发生错误了")
    print(e)
    print(type(e))
else: 
    #当没有发生异常会执行else,只能except的后面
    print("执行了else")
print("over")

语法8 try except finally

try:
    print("start")
    # a = int("abc")
    # li[1]
    # 10 / 0
    dic = {}
    # dic["name"]
    print("over")
except ValueError:
    print("值不对.....")
finally: 
    #无论是否发生异常,最后都会执行finally中的代码
    print("finally")
print("over")

finally的使用场景:

import io
# finally的使用场景,可以用finally来执行一些清理操作,类似__del__
try:
    print("start")
    f = open("a.txt","rt",encoding="utf-8")
    f.read()
    print("end")
except FileNotFoundError:
    print("文件路径错误...")
except io.UnsupportedOperation:
    print("文件不能被写入....")
finally:
    f.close()

print(f.closed)

三、自定义异常

"""
	做一个登录功能,如果登录失败就抛异常
主动抛出异常
当你写了一些功能是提供给别人用的,然而使用者不按照你的方式来使用,就会导致程序出错,而且我们无法帮助用户处理这个错误,这时候就可以主动抛出异常
raise关键字后面跟任意Exception类型的子类
  
"""

# 自定义异常类型
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()

四、断言

  1. 断言:其实就是断定的意思,确定某个条件一定成立的。有一段代码要执行必须保证某个条件是成立的
names = ["张三","李四","王麻子"]
if not names:
    raise TypeError("没有数据需要处理....")
print("正在处理这堆数据....")
print("正在处理这堆数据....")
print("正在处理这堆数据....")
#正在处理这堆数据....
#正在处理这堆数据....
#正在处理这堆数据....
===========================================
names = []
if not names:
    raise TypeError("没有数据需要处理....")
print("正在处理这堆数据....")
print("正在处理这堆数据....")
print("正在处理这堆数据....")
# raise TypeError("没有数据需要处理....")
names = []
# 使用断言来简化代码,断言后面跟一个bool类型表达式,如果结果为True则继续往下执行
# 否则直接抛出异常 AssertionError
# 其局限性是异常类型是固定的,而且不能指定异常信息
assert 1
print("正在处理这堆数据....")
print("正在处理这堆数据....")
#正在处理这堆数据....
#正在处理这堆数据....

练习:

"""
1.异常
    自定义一个Integer类
	-- 该类有个input方法,调用该方法一定会得到一个合法的数字(非数字为不合法,越界为不合法)
		---- 如果是非数字不合法,需要打印不合法消息,然后用户需要重新输入
		  -- 如输入'abc',不合法消息就为:invalid literal for int() with base 10: 'abc'
		---- 如果是越界不合法,需要打印不合法消息,然后用户需要重新输入
		  -- 如输入'2147483648',不合法消息就为:ErrorMsg:2147483648 - 越界
		提示:
		1)该方法需要捕获并处理两次异常(内置异常ValueError,自定义异常SlopOverError)
		2)该方法运用到递归方式处理更简单,如果用不到递归也可以
		
	-- 该类有个verifySlopOver方法,可以判断传入的数字是否越界(非-2147483648 ~ 2147483647为越界)
		---- 如果数字越界,会主动抛出自定义SlopOverError异常,并传入数字和异常消息
    自定义异常SlopOverError类
	-- 该类需要重写__init__方法
		---- 有num、msg两个参数,num是数字类型的数,msg是字符串类型的异常消息
	-- 该类需要重写__str__方法
		---- 通过num、msg两个属性格式化异常信息

2.元类
    自定义轿车元类CarMeta
	-- 实现元类为CarMeta的类至少有生产日期(production_date)、发动机编号(engine_number)及载客量(capacity)三个基本属性
"""
class SlopOverError(Exception):
    def __init__(self,num,msg):
        self.num = num
        self.msg = msg
    def __str__(self):
        return  "msg:%s num:%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 >  2147483648:
            raise SlopOverError(num,"数字越界 范围必须是-2147483648  到  2147483648")

res = Integer.input()
print(res)
=======================================================
class CarMeta(type):
    def __call__(self, *args, **kwargs):
        print(args)
        if len(args) < 3:
            raise ValueError("必须包含三个参数.....")
        obj = object.__new__(self)
        self.__init__(obj,*args,**kwargs)

        if not("production_date" in obj.__dict__  and "engine_number" in obj.__dict__ and "capacity" in obj.__dict__):
            raise ValueError("必须包含 生产日期,发动机编号,宰客容量")
        return obj

class BigCar(metaclass=CarMeta):
    def __init__(self,production_date,engine_number,capacity):
        self.production_date = production_date
        self.engine_number = engine_number
        self.capacity = capacity

c = BigCar("2018 12 21","xxxxxxdsb",5)
print(c)
#('2018 12 21', 'xxxxxxdsb', 5)
#<__main__.BigCar object at 0x000002A7B5537B00>g

猜你喜欢

转载自blog.csdn.net/zdc45625/article/details/85127339