Python 错误处理

Python 提供了两个重要功能来处理 Python 程序中可能出现的错误和异常:

  • 断言(Assertions)
  • 异常处理
    assert&exception

断言(Assertions)

Python assert(断言) 用于判断一个表达式,在表达式为 false 时触发异常

断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况。
assert

  • 语法

    assert expression [,arguments
    

    等同于

    if not expression:
      raise AssertionError(arguments)
    

错误和异常处理

Python 中有两种错误:

  • 语法错误(Syntax errors)
  • 异常(Exceptions)

语法错误

当 Python 代码出现语法错误时,会抛出语法错误。

>>> Print Hello,world!
  File "<stdin>", line 1
    Print Hello,world!
          ^
SyntaxError: invalid syntax

异常

语法正确的情况下,运行时出现的错误叫做异常。

>>> 10 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

异常捕获处理(try/except…else-finally语句)

try-except

  • 示例:

    while True:
        try:
            x = int(input("请输入一个数字: "))
            break
        except ValueError:
            print("您输入的不是数字,请再次尝试输入!")
    
  • 同时捕获多个异常

    except (RuntimeError, TypeError, NameError): # except 后面是多个异常组成的一个元组
    pass
    
    # Or
    
    except OSError as err:
        print("OS error: {0}".format(err))
    except ValueError:
        print("Could not convert data to an integer.")
    except:
        print("Unexpected error:", sys.exc_info()[0])
        raise
    
  • 捕获所有异常

    >>> try:
    ...     10 * (1 / 0)
    ... except:
    ...     print(”代码有错误,请检查")
      File "<stdin>", line 4
        print(”代码有错误,请检查")
                       ^
    SyntaxError: invalid character in identifier
    

抛出异常

Python 中使用 raise 语句抛出一个指定的异常
raise

示例

x = 10
if x > 5:
    raise Exception(f'x 不能大于 5, x 的值为: {x}')

try…except Exception as e语句

Exception 匹配了所有异常,把异常名称赋给了 e。相当于 Java 中的声明了一个异常对象 catch(Exeption e)

  • 示例
    try:
        10 * (1 / 0)
    except Exception as e:
        print(f"代码有异常,异常类型为:{str(e)}")
    
    # 代码有异常,异常类型为:division by zero
    

传递异常 re-raise Exception

  • 使用场景:

    • 捕捉到了异常,但是又想重新引发它(传递异常)。
    • 只想知道这是否抛出了一个异常,并不想去处理它。
  • 示例

    >>> try:
            raise NameError('HiThere')
        except NameError:
            print('An exception flew by!')
            raise
    
  • 使用单个 raise 语句的原因:

    为了保持异常的完整信息,在捕获异常后再次抛出时不能在 raise 后面加上异常对象,否则异常的 trace 信息就会从此处截断。

自定义异常

>>> class MyError(Exception):
        def __init__(self, value):
            self.value = value
        def __str__(self):
            return repr(self.value)

当做文件操作时使用内置的语法范式而不要使用 try/except-finally

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

使用 Exception 而不是 BaseException

通常情况下,当我们再程序中捕获异常时,应该使用 Exception 而不是 BaseException

Python 的异常结构如下:

BaseException          # 所有异常的基类
├── SystemExit         # 解释器请求退出
├── KeyboardInterrupt  # 用户中断执行(通常是输入^C)
├── GeneratorExit      # 生成器(generator)发生异常来通知退出
└── Exception          # 常规异常的基类

可以明显看到, BaseException 在 Python 中属于所有异常的基类Exception 继承了它。

BaseException 的子类除了包括 Exception,还包括 SystemExitKeyboardInterruptGeneratorExit 三个异常。

所以,在程序中我们更应该使用 Exception 而不是 BaseException,另外三个异常属于更高级别的异常,合理的做法应该是交给Python的解释器处理

Python 异常列表

BaseException  # 所有异常的基类
├── SystemExit  # 解释器请求退出
├── KeyboardInterrupt  # 用户中断执行(通常是输入^C)
├── GeneratorExit  # 生成器(generator)发生异常来通知退出
└── Exception  # 常规异常的基类
    ├── StopIteration  # 迭代器没有更多的值
    ├── StopAsyncIteration  # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
    ├── ArithmeticError  # 各种算术错误引发的内置异常的基类
    │   ├── FloatingPointError  # 浮点计算错误
    │   ├── OverflowError  # 数值运算结果太大无法表示
    │   └── ZeroDivisionError  # 除(或取模)零 (所有数据类型)
    ├── AssertionError  # 当assert语句失败时引发
    ├── AttributeError  # 属性引用或赋值失败
    ├── BufferError  # 无法执行与缓冲区相关的操作时引发
    ├── EOFError  # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
    ├── ImportError  # 导入模块/对象失败
    │   └── ModuleNotFoundError  # 无法找到模块或在在sys.modules中找到None
    ├── LookupError  # 映射或序列上使用的键或索引无效时引发的异常的基类
    │   ├── IndexError  # 序列中没有此索引(index)
    │   └── KeyError  # 映射中没有这个键
    ├── MemoryError  # 内存溢出错误(对于Python 解释器不是致命的)
    ├── NameError  # 未声明/初始化对象 (没有属性)
    │   └── UnboundLocalError  # 访问未初始化的本地变量
    ├── OSError  # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
    │   ├── BlockingIOError  # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
    │   ├── ChildProcessError  # 在子进程上的操作失败
    │   ├── ConnectionError  # 与连接相关的异常的基类
    │   │   ├── BrokenPipeError  # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
    │   │   ├── ConnectionAbortedError  # 连接尝试被对等方中止
    │   │   ├── ConnectionRefusedError  # 连接尝试被对等方拒绝
    │   │   └── ConnectionResetError    # 连接由对等方重置
    │   ├── FileExistsError  # 创建已存在的文件或目录
    │   ├── FileNotFoundError  # 请求不存在的文件或目录
    │   ├── InterruptedError  # 系统调用被输入信号中断
    │   ├── IsADirectoryError  # 在目录上请求文件操作(例如 os.remove())
    │   ├── NotADirectoryError  # 在不是目录的事物上请求目录操作(例如 os.listdir())
    │   ├── PermissionError  # 尝试在没有足够访问权限的情况下运行操作
    │   ├── ProcessLookupError  # 给定进程不存在
    │   └── TimeoutError  # 系统函数在系统级别超时
    ├── ReferenceError  # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
    ├── RuntimeError  # 在检测到不属于任何其他类别的错误时触发
    │   ├── NotImplementedError  # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
    │   └── RecursionError  # 解释器检测到超出最大递归深度
    ├── SyntaxError  # Python 语法错误
    │   └── IndentationError  # 缩进错误
    │       └── TabError  # Tab和空格混用
    ├── SystemError  # 解释器发现内部错误
    ├── TypeError  # 操作或函数应用于不适当类型的对象
    └── ValueError  # 操作或函数接收到具有正确类型但值不合适的参数
        ├── UnicodeError  # 发生与Unicode相关的编码或解码错误
        │   ├── UnicodeDecodeError  # Unicode解码错误
        │   ├── UnicodeEncodeError  # Unicode编码错误
        │   └── UnicodeTranslateError  # Unicode转码错误
        └── Warning  # 警告的基类
            ├── DeprecationWarning  # 有关已弃用功能的警告的基类
            ├── PendingDeprecationWarning  # 有关不推荐使用功能的警告的基类
            ├── RuntimeWarning  # 有关可疑的运行时行为的警告的基类
            ├── SyntaxWarning  # 关于可疑语法警告的基类
            ├── UserWarning  # 用户代码生成警告的基类
            ├── FutureWarning  # 有关已弃用功能的警告的基类
            ├── ImportWarning  # 关于模块导入时可能出错的警告的基类
            ├── UnicodeWarning  # 与Unicode相关的警告的基类
            ├── BytesWarning  # 与bytes和bytearray相关的警告的基类
            └── ResourceWarning  # 与资源使用相关的警告的基类。被默认警告过滤器忽略。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十甫寸木南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值