开发者

Python异常类型的使用及说明

目录
  • 一、异常的基本层次结构
  • 二、主要异常类型详解
    • 类别1:最常见的运行时错误
    • 类别2:用于程序设计和逻辑控制的异常
    • 类别3:与外部环境交互的错误
    • 类别4:算术和导入错误
    • 类别5:语法错误(特殊情况)
  • 三、创建你自己的自定义异常
    • 总结

      在python中,我们可以 raise 的 Error(更准确地说是 Exception,异常)类型非常丰富,它们构成了一个清晰的类层次结构。了解这些类型及其用途,对于编写健壮、可读性强的代码至关重要。

      NotImplementedError 是一个非常好的例子,它代表了一种特定的&jsldquo;设计意图”,而不仅仅是运行时错误。

      下面我将为您详细介绍Python中可以 raise 的主要异常类型,并按照它们的逻辑关系和用途进行分类。

      一、异常的基本层次结构

      所有Python的内置异常都继承自 BaseException 类。这个层次结构非常重要:

      BaseException
       ├── SystemExit
       ├── KeyboardInterrupt
       └── Exception  <-- 绝大多数异常都继承自这里
            ├── StopIteration
            ├── ArithmeticError
            │    ├── ZeroDivisionError
            │    └── OverflowError
            ├── AssertionError
            ├── AttributeError
            ├── ImportError
            │    └── ModuleNotFoundError
            ├── LookupError
            │    ├── IndexError
            │    └── KeyError
            ├── NameError
            ├── OSError
            │    ├── FileNotFoundError
            │    └── PermissionError
            ├── RuntimeError
            │    └── NotImplementedError  <-- 你提到的在这里
            ├── TypeError
            ├── ValueError
            └── ...等等
      

      一条黄金法则:

      在你的 try...except 语句中,通常应该捕获 Exception 或其子类,而不是 BaseException。因为 SystemExitKeyboardInterrupt 不被认为是程序“错误”,捕获它们会阻止程序正常退出或响应用户中断(Ctrl+C)。

      二、主要异常类型详解

      我将它们分为几类,以便更好地理解它们的用途。

      类别1:最常见的运行时错误

      这些是你在日常编程中遇到最多的错误。

      ValueError

      • 何时使用:当一个函数的参数类型正确,但其不合适时。
      • 示例int('abc')。字符串 'abc' 是一个 str 类型,int()编程客栈以接受 str,但 'abc' 这个值无法被转换成整数。

      TypeError

      • 何时使用:当对一个对象执行了其类型不支持的操作时。
      • 示例'hello' + 5。你不能将一个字符串和一个整数相加。

      NameError

      • 何时使用DJIbm当尝试使用一个未被定义的变量名时。
      • 示例print(my_undefined_variable)

      IndexError

      • 何时使用:当试图访问序列(如列表、元组)中一个不存在的索引时。
      • 示例my_list = [1, 2, 3]; print(my_list[5])

      KeyError

      • 何时使用:当试图访问字典中一个不存在的键时。
      • 示例my_dict = {'a': 1}; print(my_dict['b'])

      AttributeError

      • 何时使用:当试图访问或赋值一个对象不存在的属性或方法时。
      • 示例my_int = 5; my_int.append(6)。整数没有 append 方法。

      类别2:用于程序设计和逻辑控制的异常

      这类异常通常由程序员主动 raise,以表明某种设计上的约定或状态。

      NotImplementedError (继承自 RuntimeError)

      • 何时使用:在父类(尤其是抽象基类)中定义一个方法,并强制要求所有子类必须重写(实现)这个方法。它清楚地告诉其他开发者:“这个功能需要你自己去实现”。

      示例

      class Shape:
          def get_area(self):
              # 任何继承自Shape的子类都必须实现自己的get_area方法
              raise NotImplementedError("Subclasses must implement this method!")
      
      class Square(Shape):
          def __init__(self, side):
              self.side = side
          
          # 如果不写下面的方法,调用 get_area() 就会报错
          def get_area(self):
              return self.side ** 2
      
      # s = Shape()
      # s.get_area()  # 这会立即引发 NotImplementedError
      sq = Square(5)
      print(sq.get_area()) # 输出 25
      

      AssertionError

      • 何时使用:当 assert 语句的条件为 False 时被触发。它主要用于内部自检和调试,检查程序在某个点的状态是否符合预期。它不应该用于验证用户输入。

      示例

      def process_data(data):
          assert isinstance(data, list), "Input data must be a list"
          # ... 后续处理 ...
      
      process_data("not a list") # 引发 AssertionError: Input data must be a list
      

      RuntimeError

      • 何时使用:当发生一个不属于任何其他明确类别的错误时。它是一个比较通用的错误,通常表示发生了某些意想不到的外部事件。NotImplementedError 就是它的一个子类。

      类别3:与外部环境交互的错误

      OSError

      • 何时使用:当发生系统相关的错误时,例如I/O操作失败。它是一个广泛的基类。

      它的重要子类包括

      • FileNotFoundError: 试图打开一个不存在的文件。open('non_existent_file.txt')
      • PermissionError: 试图以没有权限的方式读写文件。例如,试图写入一个只读文件。
      • ConnectionError: 与网络连接相关的问题,如连接被拒绝 (ConnectionRefusedError)。
      • TimeoutError: 一个操作在指定时间内未能完成。

      类别4:算术和导入错误

      ArithmeticError

      • 何时使用:所有数值计算错误的基类。

      子类包括

      • ZeroDivisionError: 除以零。1 / 0
      • OverflowError: 计算结果超出了数字类型能表示的最大范围。import math; math.exp(1000)

      ImportError

      • 何时使用:当 import 语句无法找到或加载模块时。
      • ModuleNotFoundError (自 Python 3.6 起):是 ImportError 的一个子类,更明确地表示模块本身未找到。
      • 示例import some_module_that_does_not_exist

      类别5:语法错误(特殊情况)

      SyntaxError

      • 何时发生:这是你在运行代码之前就会遇到的错误。Python解释器在解析代码时发现语法不正确。你不能在DJIbm try...except 块中捕获它,因为它在代码执行前就失败了。
      • IndentationError (子类):最常见的语法错误之一,代码缩进不正确。

      三、创建你自己的自定义异常

      当内置的异常类型无法精确描述你的应用程序特有的错误时,最佳实践是创建自己的异常类。这能让你的代码更具可读性和可维护性。

      自定义异常应该继承自 Exception 或其某个合适的子类。

      示例:假设你在开发一个与外部API交互的应用。

      # 1. 创建一个基础的自定义异常类
      class MyAppError(Exception):
          """应用程序所有自定义异常的基类。"""
          pass
      
      # 2. 创建更具体的异常类
      class APIResponseError(MyAppError):
          """当API返回一个意外的或错误的响应时引发。"""
          def __init__(self, message, status_code):
              super().__init__(message)
              self.status_code = status_code
      
      # 3. 在代码中使用它
      def get_user_data(user_id):
          # response = requests.get(f"https://api.example.com/users/{user_id}")
          # 模拟一个失败的响应
          status_code = 500
          if status_code != 200:
              raise APIResponseError(f"Failed to fetch data, API returned {status_code}", status_code)
          # return response.json()
      
      # 4. 捕获它
      try:
          get_user_data(123)
      except APIResponseError as e:
          print(f"Error communicating with API: {e}")
          print(f"Status code was: {e.status_code}")
      except MyAppError as e:
          print(f"An application-specific error occurred: {e}")
      
      

      总结

      使用 内置异常 来表示通用的编程错误(如 ValueError, TypeError)。

      使用 NotImplementedError 来定义接口和抽象方法,强制子类实现。

      使用 AssertionError 进行内部调试和状态检查。

      当内置异常不足以描述你的特定问题域时,创建自定义异常,以提高代码的清晰度和健壮性。

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)python

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜