Python中的异常

1. 概述

使用try…except语句块处理异常。
try语句的工作原理是:

  • 首先,执行 try 子句 (try 和 except 关键字之间的(多行)语句)。
  • 如果没有异常发生,则跳过 except 子句 并完成 try 语句的执行。
  • 如果在执行 try 子句时发生了异常,则跳过该子句中剩下的部分。 然后,如果异常的类型和 except 关键字后面的异常匹配,则执行 except 子句,然后继续执行 try 语句之后的代码。
  • 如果发生的异常和 except 子句中指定的异常不匹配,则将其传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常,执行将停止。

一个 try 语句可能有多个 except 子句,以指定不同异常的处理程序,最多只会执行一个处理程序。处理程序只处理相应的 try 子句中发生的异常,而不处理同一 try 语句内其他处理程序中的异常。
最后的 except 子句可以省略异常名,以用作通配符。

2. 处理异常

2.1 一个except语句只处理一个异常(如ValueError异常)

while True:
    try:
        x = int(input('Please enter a number: '))
        break
    except ValueError:
        print("Oops!  That was no valid number.  Try again...")

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
Please enter a number: d
Oops!  That was no valid number.  Try again...
Please enter a number: 12

Process finished with exit code 0

2.2 一个except语句处理多个异常

一个 except 子句可以将多个异常命名为带括号的元组,即同时处理多个异常。

while True:
    try:
        x = int(input('Please enter a number: '))
        break
    except (RuntimeError, TypeError, NameError,ValueError):
        print("Oops!  That was no valid number.  Try again...")

2.3 处理有继承关系的异常类

如果发生的异常和 except 子句中的类是同一个类或者是它的基类,则异常和 except 子句中的类是兼容的;但是反过来不成立,except子句中的派生类不能处理来自基类的异常。

class ExceptionBase(Exception):
    pass

class ExceptionA(ExceptionBase):
    pass

class ExceptionB(ExceptionA):
    pass

for cls in [ExceptionBase, ExceptionA, ExceptionB]:
    try:
        raise cls()
    except ExceptionB:
        print("ExceptionB")
    except ExceptionA:
        print("ExceptionA")
    except ExceptionBase:
        print("ExceptionBase")

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
ExceptionBase
ExceptionA
ExceptionB

Process finished with exit code 0

2.3 except通配符处理所有未处理的异常

最后的 except 子句可以省略异常名,以用作通配符。

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
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

2.4 try … except 语句可选的 else 子句

可选的 else 子句,在使用时必须放在所有的 except 子句后面。在 try 子句不引发异常时才会执行的else子句的代码。

class ExceptionBase(Exception):
    pass

class ExceptionA(ExceptionBase):
    pass

class ExceptionB(ExceptionA):
    pass

for cls in [ExceptionBase, ExceptionA, ExceptionB]:
    try:
        raise cls()
    except ExceptionB:
        print("ExceptionB")
    except ExceptionA:
        print("ExceptionA")
    except ExceptionBase:
        print("ExceptionBase")
    else:
        print('There is no exception')

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
ExceptionBase
ExceptionA
ExceptionB

Process finished with exit code 0

2.5 try … except 语句可选的 finally 子句

finally子句在try…except执行完后,最后必执行。
finally子句执行的情况:

  • 如果在执行 try 子句期间发生了异常,该异常可由一个 except 子句进行处理。 如果异常没有被某个 except 子句所处理,则该异常会在 finally 子句执行之后被重新引发。
  • 异常也可能在 except 或 else 子句执行期间发生。 同样地,该异常会在 finally 子句执行之后被重新引发。
  • 如果在执行 try 语句时遇到一个 break, continue 或 return 语句,则 finally 子句将在执行 break, continue 或 return 语句之前被执行。
  • 如果 finally 子句中包含一个 return 语句,则返回值将来自 finally 子句的某个 return 语句的返回值,而非来自 try 子句的 return 语句的返回值。
try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
else:
    print('There is no exception')
finally:
    print('-----finally-----')

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
An exception flew by!
-----finally-----

Process finished with exit code 0

2.6 带参数的异常

except 子句可以在异常名称后面跟 as 关键字指定一个异常类的实例,它的参数存储在 instance.args 中。

try:
    raise Exception('spam', 'eggs')
except Exception as inst:
    print(type(inst))    # the exception instance
    print(inst.args)     # arguments stored in .args
    print(inst)          # __str__ allows args to be printed directly,
                         # but may be overridden in exception subclasses
    x, y = inst.args     # unpack args
    print('x =', x)
    print('y =', y)
else:
        print('There is no exception')

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

Process finished with exit code 0

3. 抛出异常

使用关键字raise 抛出异常。
raise 唯一的参数就是要抛出的异常,这个参数必须是一个异常实例或者是一个异常类(派生自 Exception 的类)。如果传递的是一个异常类,它将通过调用没有参数的构造函数来隐式实例化:

raise ValueError  # shorthand for 'raise ValueError()'

如果你需要确定是否引发了异常但不打算处理它,则可以使用更简单的 raise 语句形式重新引发异常:

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
    raise

输出:

D:\Work\PRJS\pythonProject\pythonProject4\venv\Scripts\python.exe D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py
An exception flew by!
Traceback (most recent call last):
  File "D:/Work/PRJS/pythonProject/pythonProject4/venv/MyException.py", line 2, in <module>
    raise NameError('HiThere')
NameError: HiThere

Process finished with exit code 1

4. 自定义异常类

程序可以通过创建新的异常类来命名它们自己的异常,异常通常应该直接或间接地从 Exception 类派生。
可以定义异常类,它可以执行任何其他类可以执行的任何操作,但通常保持简单,只提供一些属性,这些属性允许处理程序为异常提取有关错误的信息。
在创建可能引发多个不同错误的模块时,通常的做法是为该模块定义的异常创建基类,并为不同错误条件创建特定异常类的子类:

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

[上一页][下一页]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值