Python学习笔记19_异常处理

Python学习笔记19_异常处理

1、异常

  • 运行期检测到的错误被称为异常
  • 常见的异常:
    • 0 作为除数
    • 使用未定义变量
    • ……
  • 异常不同于语法错误,多数时候是由于逻辑错误或者内存错误引起。
>>> 10 * (1/0)             # 0 不能作为除数,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
    
    
>>> 4 + spam*3             # spam 未定义,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
    
    
>>> '2' + 2               # int 不能与 str 相加,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

2、异常处理

2.1、try/except

1)使用 try/except 进行异常处理的语法:

try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
while True:
    try:
        x = int(input("请输入一个数字: "))
        break
    except ValueError:
        print("您输入的不是数字,请再次尝试输入!")

2)try/except 语句的工作方式:

  • 首先,执行 try 子句(在关键字 try 和关键字 except 之间的代码块,通过缩进来区分);
  • 如果没有异常发生,忽略 except 子句,try 子句执行后结束;
  • 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行;
  • 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中;
  • 一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常。最多只有一个分支会被执行;
  • 处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常;
  • 一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组:
except (RuntimeError, TypeError, NameError):
    代码块
  • 最后一个 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.2、try/except…else

  • try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。
  • else 子句将在 try 子句没有发生任何异常的时候执行。
  • 使用格式:
try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
else:
	try 代码块执行完,没有异常时,执行的代码块
# 在 try 语句中判断文件是否可以打开,如果打开文件时正常的没有发生异常则执行 else 部分的语句,读取文件内容
for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()
  • 使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到,而 except 又无法捕获的异常。
  • 异常处理并不仅仅处理那些直接发生在 try 子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常:
>>> def this_fails():
        x = 1/0
   
>>> try:
        this_fails()
    except ZeroDivisionError as err:
        print('Handling run-time error:', err)
   
Handling run-time error: int division or modulo by zero

2.3、try-finally 语句

  • try-finally 语句无论是否发生异常都将执行最后的代码
  • 使用格式:
try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
else:
	try 代码块执行完,没有异常时,执行的代码块
finally:
    执行完前面那一堆之后,继续执行这一个代码块

3、抛出异常

  • Python 使用 raise 语句抛出一个指定的异常。
  • raise语法格式:
raise [Exception [, args [, traceback]]]
# 如果 x 大于 5 就触发异常
x = 10
if x > 5:
    raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
    
'''
输出结果:
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
'''
  • raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)
  • 如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出:
>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

4、用户自定义异常

  • 可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承:
>>> class MyError(Exception):
        def __init__(self, value):
            self.value = value
        def __str__(self):
            return repr(self.value)
   
>>> try:
        raise MyError(2*2)
    except MyError as e:
        print('My exception occurred, value:', e.value)
   
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'
  • 当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
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

5、with 关键字

  • Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式
  • 关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法
# 如果在调用 write 的过程中,出现了异常,则 close 方法将无法被执行,因此资源就会一直被该程序占用而无法被释放
file = open('./test.txt', 'w')
file.write('hello world !')
file.close()
# 对可能发生异常的代码处进行 try 捕获,发生异常时执行 except 代码块,finally 代码块是无论什么情况都会执行,所以文件会被关闭,不会因为执行异常而占用资源。
file = open('./test.txt', 'w')
try:
    file.write('hello world')
finally:
    file.close()
# 使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的
with open('./test.txt', 'w') as file:
    file.write('hello world !')
    
 # 查看文件是否关闭
>>> f.closed
True

猜你喜欢

转载自blog.csdn.net/qq_38342510/article/details/124923690