翼度科技»论坛 编程开发 python 查看内容

python学习笔记:第九章异常

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
1.1 异常是什么

python使用异常对象来表示异常状态,并在遇到错误时引发异常。异常对象未被处理,程序将终止并显示一条错误信息。
我们可以通过各种方法引发和捕获错误,并采取对应措施。
1.2 将“错误”变成异常

自主地引发异常
1.2.1 raise语句

我们通过预测异常可能发生的位置,通过raise语句主动抛出异常,用except语句来接收前面出现的异常,并作出对应的操作
  1. def divide(x, y):
  2.     if y == 0:
  3.             # 引出异常
  4.         raise ZeroDivisionError("Division by zero!")
  5.     else:
  6.         return x / y
  7. # 测试
  8. try:
  9.     result = divide(6, 0)
  10. # 接收异常
  11. except ZeroDivisionError as ex:
  12.     print(f"Error: {str(ex)}")
  13. else:
  14.     print(result)
  15. > Error: Division by zero!
复制代码
一些常见的内置异常类
  1. Exception   # 几乎所有异常类均由这个派生而来
  2. AttributeError        试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
  3. IOError        输入/输出异常;基本上是无法打开文件
  4. ImportError        无法引入模块或包;基本上是路径问题或名称错误
  5. IndentationError        语法错误(的子类) ;代码没有正确对齐
  6. IndexError        下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
  7. KeyError        试图访问字典里不存在的键
  8. KeyboardInterrupt        Ctrl+C被按下
  9. NameError        使用一个还未被赋予对象的变量
  10. SyntaxError        Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
  11. TypeError        传入对象类型与要求的不符合
复制代码
1.3 自定义的异常类

首先,要直接或间接地继承Exception类
格式
  1. class 异常类名(Exception):
  2.         pass
复制代码
利用自定义的异常类对1.2中的例子进行改进
  1. class MyException(Exception):  # 自定义异常类
  2.     pass
  3. def divide(x, y):
  4.     if y == 0:
  5.         raise MyException("Division by zero!")
  6.     else:
  7.         return x / y
  8. # 测试
  9. try:
  10.     result = divide(6, 0)
  11. except MyException as ex:
  12.     print(f"Error: {str(ex)}")
  13. else:
  14.     print(result)
复制代码
1.3.1一个具体使用场景

检查用户输入的邮件格式,不对则报错
  1. class InvalidEmailException(Exception):
  2.     def __init__(self, email):
  3.         self.email = email
  4.         self.message = f"{email} is not a valid email address. Please try again."
  5.         super().__init__(self.message)
  6. def send_email(to, subject, body):
  7.     if "@" not in to:
  8.         raise InvalidEmailException(to)  # 抛出异常
  9.     print(f"Email sent to {to} with subject '{subject}' and body '{body}'.")
  10. # 测试
  11. try:
  12.     send_email("invalid-email", "Test email", "This is a test email.")
  13. except InvalidEmailException as ex:
  14.     print(f"Error: {ex.message}")
复制代码
第五行super().__init__(self.message) 调用基类 Exception 的构造函数来初始化 self.message。
Exception的构造函数:
  1. class Exception(BaseException):
  2.     def __init__(self, *args: object) -> None:
  3.         """
  4.         Initialize self.  See help(type(self)) for accurate signature.
  5.         """
  6.         pass
复制代码
构造函数接受可变长度的参数 *args,但是它并没有执行任何实际操作,只是一个空的 pass 语句。这意味着,我们可以在自定义异常类的构造函数中调用父类 Exception 的构造函数,同时传递自定义的错误消息作为参数。
关于第五行的作用:

  • 第5行的作用只是使用基类 Exception 的构造函数,来完成可能会影响异常的某些其他行为,如设置异常的堆栈跟踪信息等。这些信息可以帮助程序员更轻松地找到代码中发生异常的位置。
    因此,虽然第5行实际上不是非常必要,但它是一个良好的实践,可以帮助进一步丰富异常信息。
  • 个人认为,可以通过重写Exception的构造函数
  • 猜想:可能会定义多个自定义类,通过定义Exception参数的方式,进行类之间的异常信息传递
1.3.2 同时监测多种异常

将异常类型以元组形式展现(没有采用raise,等待程序抛出异常并接收)
  1. class CustomException(Exception):
  2.     def __init__(self, message):
  3.         super().__init__(message) # 与上个程序第五行同理
  4. # 若出现异常,则要求用户重新输入
  5. while True:
  6.     try:
  7.         # 获取用户输入的除数和被除数
  8.         divisor = int(input("Enter the divisor: "))
  9.         dividend = int(input("Enter the dividend: "))
  10.         result = dividend / divisor
  11.     # 通过元组进行多种异常监测
  12.     except (ZeroDivisionError, TypeError, ValueError) as ex:
  13.         # 捕获多种异常
  14.         print(ex)
  15.     else:
  16.         print(f"The result of division is: {result}")
  17.         break  # 成功即跳出循环
复制代码
运行结果
  1. Enter the divisor: 0
  2. Enter the dividend: 1
  3. division by zero
  4. Enter the divisor: we
  5. invalid literal for int() with base 10: 'we'
  6. Enter the divisor: 2
  7. Enter the dividend: 1
  8. The result of division is: 0.5
复制代码
1.3.3 一网打尽的异常和else

同时监测多个异常可能不够,可以一网打尽
  1. # 若出现异常,则要求用户重新输入
  2. while True:
  3.     try:
  4.         # 获取用户输入的除数和被除数
  5.         divisor = int(input("Enter the divisor: "))
  6.         dividend = int(input("Enter the dividend: "))
  7.         result = dividend / divisor
  8.     # 通过元组进行多种异常监测
  9.     except Exception as ex:   
  10.     #对所有Exception的子类异常进行监测,只有发生了对应的子类异常,才会被捕获
  11.         # 捕获多种异常
  12.         print(ex)
  13.     else:  # 通过else语句实现循环,这里是except语句的else, 当不执行except语句时,执行else
  14.         print(f"The result of division is: {result}")
  15.         break  # 成功即跳出循环
复制代码
运行结果
  1. Enter the divisor: er
  2. invalid literal for int() with base 10: 'er'
  3. Enter the divisor: 0
  4. Enter the dividend: 1
  5. division by zero
  6. Enter the divisor: 1
  7. Enter the dividend: 2
  8. The result of division is: 2.0
复制代码
tip:
在编写代码时,最好不要捕获所有异常类型。我们应该尽可能地特定地捕获那些预期的、已知的异常类型,并将其他异常类型传递给更高层的异常处理机制进行处理。这样可以更加有效地调试和解决问题,而且代码更加可读和可维护。
1.3.4 最后的finally

无论是否发生异常,finally语句均会运行。多用于执行清理工作。
如:关闭文件,关闭网络套接字等
  1. try:
  2.     1 / 2
  3. except NameError:
  4.     print("Unknown wariable")
  5. else:
  6.     print('That went well')
  7. finally:
  8.     print('Cleaning up.')
复制代码
运行结果
  1. That went well
  2. Cleaning up.
复制代码
1.3.5 异常的传递

如果不处理函数中引发的异常,它将向上传播到调用函数中,直到主程序,若主程序中还是不能处理异常,程序将通知并显示站跟踪信息。
  1. def faulty():
  2.     raise Exception("wrong")
  3. def ig_exception():
  4.     faulty()
  5. def hl_exception():
  6.     try:
  7.         faulty()
  8.     except:
  9.         print('Exception handled')
  10. ig_exception()
复制代码
运行结果:打印了栈跟踪信息和异常信息
  1. Traceback (most recent call last):
  2.   File "d:\M\github\Python\Demo\t12.py", line 12, in <module>
  3.     ig_exception()
  4.   File "d:\M\github\Python\Demo\t12.py", line 5, in ig_exception
  5.     faulty()
  6.   File "d:\M\github\Python\Demo\t12.py", line 2, in faulty
  7.     raise Exception("wrong")
  8. Exception: wrong
复制代码
若是只调用hl_exception() 异常会被处理,程序不会终止
  1. hl_exception()
  2. print("hello")  # 打印出结果,说明程序未终止,仍在运行
  3. > Exception handled
  4. > hello
复制代码
1.4 异常之禅


  • 除了使用try/except语句来处理异常外,还可以使用if/else语句,只是不推荐这样做
  • 可以检查对象是否包含特定的属性
  1. try:
  2.         obj.write
  3. except AttributeError:
  4.         print('The object is not worteable')
  5. else:
  6.         print('The object is writeable')
复制代码

  • 不那么异常的时候,可以发出警告,由模块warning 中的函数warn提供
  1. from warnings import warn
  2. warn('got a bad feeling.')
  3. print('hello')   # 可以打印,说明程序仍在运行
  4. >
  5. d:\M\github\Python\Demo\t12.py:2: UserWarning: got a bad feeling.
  6.   warn('got a bad feeling.')
  7. hello
复制代码
来源:https://www.cnblogs.com/lmc7/p/17550305.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具