零基础入门学Python(九)—— 异常处理

零基础入门学Python系列内容的学习目录 → \rightarrow →零基础入门学Python系列内容汇总

  需要学习的基础知识有:异常处理、 try-except语句、try-finally语句、raise语句、else语句、with语句等。

1. 一些异常

  什么是异常呢?举个例子:

file_name = input('请输入要打开的文件名:')
f = open(file_name, 'r')
print('文件的内容是:')

for each_line in f:
    print(each_line)

  对于上面的这段程序,如果用户输入一个不存在的文件名,那么就会报错,抛出一个FileNotFoundError异常。
  >>>
  请输入要打开的文件名:python
  Traceback (most recent call last):
    File “C:/Users/123/Desktop/1.py”, line 2, in < module >
     f = open(file_name, ‘r’)
  FileNotFoundError: [Errno 2] No such file or directory: ‘python’

  下面列举一些异常。

  • 1.  AssertionError:断言语句(assert)失败
      当assert这个关键字后边的条件为假的时候,程序将停止并抛出AssertionError异常。assert语句一般是在测试程序的时候用于在代码中置入检查点:
      example1:>>> my_list = [“python”]
           >>> assert len(my_list) > 0
           >>> my_list.pop()
           ‘python’
           >>> assert len(my_list) > 0
           Traceback (most recent call last):
             File “<pyshell#4>”, line 1, in < module >
              assert len(my_list) > 0
           AssertionError
  • 2.  AttributeError:尝试访问未知的对象属性
      当试图访问的对象属性不存在时抛出的异常:
      example2:>>> my_list = [ ]
           >>> my_list.python
           Traceback (most recent call last):
             File “<pyshell#6>”, line 1, in < module >
              my_list.python
           AttributeError: ‘list’ object has no attribute ‘python’
  • 3.  IndexError:索引超出序列的范围
      在使用序列的时候就常常会遇到IndexError异常,原因是索引超出序列范围的内容:
      example3:>>> my_list =[1, 2, 3]
           >>> my_list[3]
           Traceback (most recent call last):
             File “<pyshell#8>”, line 1, in < module >
              my_list[3]
           IndexError: list index out of range
  • 4.  KeyError:字典中查找一个不存在的关键字
      当试图在字典中查找一个不存在的关键字时就会引发KeyError异常,因此建议使用dict.get()方法:
      example4:>>> my_dict = {“one”:1, “two”:2, “three”:3}
           >>> my_dict[“one”]
           1
           >>> my_dict[“four”]
           Traceback (most recent call last):
             File “<pyshell#11>”, line 1, in < module >
              my_dict[“four”]
           KeyError: ‘four’
  • 5.  NameError:尝试访问一个不存在的变量
      当尝试访问一个不存在的变量时,Python会抛出NameError异常:
      example5:>>> python
           Traceback (most recent call last):
             File “<pyshell#12>”, line 1, in < module >
              python
           NameError: name ‘python’ is not defined
  • 6.  OSError:操作系统产生的异常
      OSError顾名思义就是操作系统产生的异常,像打开一个不存在的文件会引发FileNotFoundError,而这个FileNotFoundError就是OSError的子类。
  • 7.  SyntaxError:Python的语法错误
      如果遇到Syntaxtrror是Python的语法错误,这时Python的代码并不能继续执行,你应该先找到并改正错误:
      example6:>>> print “Hello, python!”
           SyntaxError: Missing parentheses in call to ‘print’
  • 8.  TypeError:不同类型间的无效操作
      有些类型不同是不能相互进行计算的,否则会抛出TypeError异常:
      example7:>>> 1 + “1”
           Traceback (most recent call last):
             File “<pyshell#16>”, line 1, in < module >
              1 + “1”
           TypeError: unsupported operand type(s) for +: ‘int’ and ‘str’
  • 9.  ZeroDivisionError:除数为零
      除数为零就会引发ZeroDivisionError异常:
      example8:>>> 5 / 0
           Traceback (most recent call last):
             File “<pyshell#17>”, line 1, in < module >
              5 / 0
           ZeroDivisionError: division by zero

  如果程序抛出异常就说明这个程序有问题,我们可以通过捕获这些异常去纠正这些错误。那应该如何捕获和处理异常呢?
  异常捕获可以使用try语句来实现,任何出现在try语句范围内的异常都会被及时捕获到。try语句有两种实现形式:一种是try-except另一种是try-finally

2. try-except 语句

  try-except语句格式如下:

try:
    检测范围
except Exception [as reason]:
    出现异常(Exception)后的处理代码

  try-except语句用于检测和处理异常。
  看一个例子:

f = open('文档.txt')
print(f.read())
f.close()

  以上代码在“文档.txt”这个文档不存在的时候,Python就会报错说文件不存在:
  >>>
  Traceback (most recent call last):
    File “<pyshell#19>”, line 1, in < module >
     f = open(‘文档.txt’)
  FileNotFoundError: [Errno 2] No such file or directory: ‘文档.txt’
  >>>
  显然这样的用户体验不好,因此可以这么修改:

try:
    f = open('文档.txt')
    print(f.read())
    f.close()
except OSError:
    print('文件打开的过程中出错了!')

  >>>
  文件打开的过程中出错了!
  >>>
  但是从程序员的角度来看,导致OSError异常的原因有很多(例如FileExistsErrorFileNotFoundErrorPermissionError等等),所以想要直到错误的具体内容,可以用as把具体的错误信息给打印出来:

try:
    f = open('文档.txt')
    print(f.read())
    f.close()
except OSError as reason:
    print('文件出错了! \n错误原因是:' + str(reason))

  >>>
  文件出错了!
  错误原因是:[Errno 2] No such file or directory: ‘文档.txt’
  >>>

2.1 针对不同异常设置多个except

  一个try语句还可以和多个except语句搭配,分别对感兴趣的异常进行检测处理:

try:
    sum = 1 + '1'
    f = open('文档.txt')
    print(f.read())
    f.close()
except OSError as reason:
    print('文件出错了! \n错误原因是:' + str(reason))
except TypeError as reason:
    print('类型出错了! \n错误原因是:' + str(reason))

  >>>
  类型出错了!
  错误原因是:unsupported operand type(s) for +: ‘int’ and ‘str’
  >>>

2.2 对多个异常统一处理

  except后边还可以跟多个异常,然后对这些异常进行统一的处理:

try:
    int('abc')
    sum = 1 + '1'
    f = open('文档.txt')
    print(f.read())
    f.close()
except (OSError, TypeError) as reason:
    print('文件出错了! \n错误原因是:' + str(reason))

2.3 捕获所有异常

  如果我们无法确定要对哪一类异常进行处理,只是希望在try语句块里一旦出现任何异常,可以给用户一个“看得懂”的提醒,那么可以这么做:

...
except (OSError, TypeError) as reason:
     print('出错啦~')
...

  不过通常不建议这么做,因为它会隐藏所有程序员未想到并且未做好处理准备的错误,例如当用户输入Ctrl+C试图终止程序,却被解释为KeyboardInterrupt异常。另外要注意的是,try语句检测范围内一旦出现异常,剩下的语句将不会被执行。

3. try-finally 语句

  如果“文档.txt”确实存在,open()函数正常返回文件对象,但异常却发生在成功打开文件后的sum=1 + '1'语句上。此时Python将直接跳到except语句,也就是说,文件打开了,但并没有执行关闭文件的命令:

try:
    f = open('文档.txt')
print(f.read())
    sum = 1 + '1'
    f.close()
except:
    print('出错了!')

  为了实现像这种“就算出现异常,但也不得不执行的收尾工作(比如在程序崩溃前保存用户文档)”,引入了finally来扩展try

try:
    f = open('文档.txt')
print(f.read())
    sum = 1 + '1'
except:
    print('出错了!')
finally:
    f.close()

  如果try语句块中没有出现任何运行时错误,会跳except语句块执行finally语句块内容。如果出现异常,则会先执行except语句块的内容再执行finally语句块的内容。总之finally语句块中的内容就是确保无论如何都将被执行的内容。

4. raise语句

  可以使用raise语句让代码自己抛出一个异常:
  >>> raise ZeroDivisionError
  Traceback (most recent call last):
    File “<pyshell#0>”, line 1, in < module >
     raise ZeroDivisionError
  ZeroDivisionError

  抛出的异常还可以带参数,表示异常的解释:
  >>>raise ZeroDivisionError(“除数不能为零!”)
  Traceback(most recent call last):
   File"<pyshell#2>",1ine 1,in< module >
    raise ZeroDivisionError(“除数不能为零!”)
  ZeroDivisionError:除数不能为零!

5. 丰富的else语句

  在Python中,else语句不仅能跟if语句搭,构成“要么怎样,要么不怎样”的句式;它还能跟循环语句(for语句或者while语句),构成“干完了能怎样,干不完就别想怎样”的句式;其实else语句还能够跟刚刚的异常处理进行搭配,构成“没有问题?那就干吧”的句式,下边逐个进行解释。

  • 1.要么怎样,要么不怎样
      典型的if-else搭配:
if 条件:
    条件为真执行
else:
    条件为假执行
  • 2.干完了能怎样,干不完就别想怎样
      else可以跟forwhile循环语句配合使用,但else语句块只在循环完成后执行,也就是说,如果循环中间使用break语句跳出循环,那么else里边的内容就不会被执行了。
def showMaxFactor(num):
    count = num // 2
    while count > 1:
        if num % count == 0:
            print('%d最大的约数是%d'%(num, count))
            break
        count -= 1
   else:
        print('%d是素数!'% num)

num = int(input('请输入一个数:'))
showMaxFactor(num)

  这段代码主要是求用户输入的数的最大约数,如果是素数的话打印这是一个素数。注意要使用地板除(count=num//2),否则结果会出错。使用暴力的方法一个个尝试(num % count==0),如果符合条件则打印出最大的约数,并break,同时不会执行else语句块的内容了。但如果一直没有遇到合适的条件,则会执行else语句块内容。
  for语句的用法跟while一样。

  • 3.没有问题?那就干吧
      else语句还能跟异常处理进行搭配,实现跟与循环语句搭配差不多:只要try语句块里没有出现任何异常,那么就会执行else语句块里的内容。
try:
    int('abc')
except ValueError as reason:
    print(出错啦: + str(reason)) 
else:
    print('没有任何异常!')
6. 简洁的with语句

  打开文件又要关闭文件,还要关注异常处理会有点麻烦,所以Python提供了一个with语句,利用这个语句抽象出文件操作中频繁使用的try/except/finally相关的细节。对文件操作使用with语句,将大大减少代码量,而且再也不用担心出现文件打开了记关闭的问题了(with会自动帮我们关闭文件)。

try:
    f=open('data.txt', 'w')
    for each_line in f:
        print(each_line)
except OSError as reason:
    print('出错啦:' + str(reason))
finally:
    f.close()

  使用with语句,可以改成这样:

try:
    with open('data.txt', 'w')as f:
        for each_line in f:
            print(each_line)
except OSError as reason:
    print('出错啦:' + str(reason))

  有了with语句,我们就再也不用担心忘记关闭文件了。

上一篇:异常处理


下一篇:python-模块