【Python】异常与捕获

332 阅读5分钟

当检测到⼀个错误时,解释器就无法继续执行了,反而出现了⼀些错误的提示,这就是所谓的"异常"。

Python 提供了两个非常重要的功能来处理程序在运行中出现的异常和错误。我们可以使用该功能来调试程序。

什么是异常:

  • 异常是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行;
  • 一般情况下,在 Python 无法正常处理程序时会发生一个异常;
  • 异常是 Python 对象,表示一个错误(bug)
  • 当 Python 脚本发生异常时我们需要捕获处理,否则程序不会继续执行。

异常语法:

try:
    程序正常执行此块代码
except:
    错误时执行此块代码并抛出异常

常见异常:

image.png

简易示例:

try:
    # 程序正常执行
    num = input('请输入:')
    number = float(num)
    print(number)
except:
    # 当程序达到某个条件时:
    number = 1
    print(number)

解析: 上述示例,虽然不报错,但无法记录具体的异常种类,若需记录具体的异常种类,则需捕获该具体异常。语法如下:

"""语法:
try:
    pass
except 当前异常对象 as e:   # e = 当前异常对象
    print(e)
"""

先来看一下,不捕获异常的写法:程序无法继续执行;

li = [1, 2, 3, 4, 5]
print(li[6])    # 报错:IndexError: list index out of range

a = 1
b = 0
c = a / b
print(c)   # 报错:ZeroDivisionError: division by zero

print(int('a'))   # 报错:ValueError: invalid literal for int() with base 10: 'a'

再来看一下捕获异常:能够抛出具体的异常,且不影响程序执行;

try - except:

try:
    li = [1, 2, 3, 4, 5]
    print(li[6])
# except IndexError as e:  # e = IndexError,这种方法仅能捕获这一种异常类型
# print(e)
except Exception as e:  # 通过共同的父类Exception捕获输出
    # 类的实例对象调用__class__属性时会指向该实例对应的类,而后再调用__name__,输出该实例对应的类的类名
    print(e.__class__.__name__, ":", e, '---')  # IndexError : list index out of range ---

try - except - else:

  • 如果抛出异常,执行 except 内容代码
  • 如果正常执行,程序执行 else 内部代码
try:
    li = [1, 2, 3, 4, 5]
    print(li[8])

# 如果抛出异常,执行except内部代码
except Exception as e:
    print(e.__class__.__name__, ":", e, '糟糕,报错了。')

# 如果正常执行,程序执行else内部代码
else:
    print('哈哈哈')
    
输出结果:
IndexError : list index out of range 糟糕,报错了。

try - except - finally:

不管程序有无发生异常,都会执行 finally 内部代码;

try:
    li = [1, 2, 3, 4, 5]

# 如果抛出异常,执行 except 内部代码
except Exception as e:
    print(e.__class__.__name__, ":", e, '。')

# 如果正常执行,程序执行 else 内部代码
else:
    print('很晚了,该睡觉了。')

# 不管程序有无发生异常,都会执行 finally 内部的代码
finally:
    print('卷不动了,睡觉吧')
    
输出结果:
很晚了,该睡觉了。
卷不动了,睡觉吧

主动触发异常:

在实际开发中,当程序不满足某条件时,通常会主动抛出异常。

语法:
raise Exception()

代码实例:

# 判断煎饼熟了没,当烹饪时间小于5时,则主动触发没熟异常;否则熟了。


# 定义一个函数,给一个形参(时间)
def demo(time):
    if time < 5:
        # 不满足条件,主动抛出异常
        raise Exception('别着急呀,还没熟呢...')


try:
    demo(4)   # 调用函数,并传入实参
except Exception as e:
    print("不满足条件时,主动抛出异常:", e)
else:
    print('哇,已经熟了,快来吃吧..')
    
输出结果:
不满足条件时,主动抛出异常: 别着急呀,还没熟呢...

实例2:

def test(a, b):
    if b == 0:
        raise ZeroDivisionError("零不可以成为分子")
    return a / b


try:
    test(1, 0)
except Exception as e:
    print(e)
    
输出结果:
零不可以成为分子

自定义异常:

当需要自定义满足一些规则时,需自定义异常;
自定义异常:通过创建一个新的异常类,自定义名字与内容,并且需要继承Exception类实现。

代码实例:

# 判断密码长度  如果密码长度小于6,则主动触发异常、并抛出异常信息(打印提示)

class shortInputError(Exception):

    # 初始化
    def __init__(self, lenth, min_len):

        # 输入的密码长度
        self.lenth = lenth

        # 要求密码的最小长度
        self.min_len = min_len

    # 自定义输出
    def __str__(self):
        return f"你输入的密码长度为{self.lenth},要求不能少于{self.min_len}位,请核对。"
        

def demo():
    try:
        pwd = input("请输入密码:")
        if len(pwd) < 6:
        
            # 主动触发异常
            raise shortInputError(len(pwd), 6)
            
    except Exception as e:
        print(e)  # 主动触发的异常,在这里打印

    else:
        print('输入的密码符合要求。')


demo()

断言:

用于判断一个表达式,当表达式条件为F时触发断言异常 AssertionError;

使用python中的断言来自动检测python程序中的错误,让程序更加可靠且更易于调试:

从根本上来说,python中的断言语句是一种调试工具,用来测试某个断言条件。

如果断言条件为 True,则程序将继续正常执行;

如果断言条件为假 False,则会引发 AssertionError 异常并显示相关的错误消息。

语法:
assert 断言

代码实例:

# 以618球拍折扣为例:

def applyDiscount(racket, discount):
    
    disPrice = int(racket['price']) * (1 - discount)

    # 该语句确保在任何情况下,通过该函数计算的折后价格不低于0,也不会高于产品原价。
    assert 0 <= disPrice <= racket['price']
    return price


if __name__ == '__main__':
    racket = {
        'name': '尤尼克斯',
        'price': 3200,
    }
    price = applyDiscount(racket, 2)
    print(f'折扣后的球拍价格为{price}元')

当尝试使用反常的折扣时,比如:把商品打200%的折扣,

image.png 我们会看到,程序停止,并且触发一个 AssertionError。

这是因为不满足上述示例,applyDiscount中设置的断言条件。