likes
comments
collection
share

零基础学习 Python 之错误 & 异常

作者站长头像
站长
· 阅读数 7

写在前面

对于程序在执行过程中因为错误或者其它原因而中止的现象,相信大家已经看过很多次了,那些都可以归为「错误 & 异常」现象,我们接下来就是要对这种现象进行近距离的观察和处理。

错误

其实不管是弱鸡还是大佬,在写代码的时候错误往往是难以避免的,可能是因为手残,也可能是因为拼写错误,当然还有可能是某些比较玄学的错误,比如逗号写成全角的等等等等。总之,写代码中有相当一部分工作就是要不停的修改错误。

Python 中的错误之一就是「语法错误」(Syntax Errors),比如:

>>> for i in range(5)

 File "<stdin>", line 1

   for i in range(5)

                   ^
SyntaxError: invalid syntax

上面的那行代码里因为缺少冒号,导致解释器无法解释,于是报错,这个报错其实是 Python 的语法分析器完成的,并检测到了错误所在的文件和行号( File "", line 1 ),还以向上的箭头 ^ 标识错误的位置,最后显示错误类型。

另一种错误就是我们常说的「逻辑错误」,逻辑错误可能是由不合法或者不完整的输入导致的,也可能是无法计算等,或者是其它的逻辑问题。逻辑错误不是由 Python 来检查的,所以此处我们所谈的错误不包括逻辑错误。

异常

当 Python 检测到一个错误时,解释器就无法继续执行下去,于是就抛出提示信息,即为「异常」。有错误时,程序运行过程就会出现异常,让我们先来看一个小例子:

>>> 10 / 0

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

ZeroDivisionError: division by zero

当 Python 抛出异常的时候,首先有「跟踪记录」或者叫「回溯」,后面显示异常的详细信息,包括异常所在的位置,最后一行是异常类型及导致异常的原因。在上面的例子中,明确的告诉我们异常的类型是 ZeroDivisionError,并且对此异常类型做了解释。

异常的类型有很多,我在这说几个常见的类型:

NameError

尝试访问一个没有申明的变量

ZeroDivisionError

除数为零

SyntaxError

语法错误

IndexError

索引超出序列范围

KeyError

请求一个不存在的字典关键字

IOError

输入/输出错误

AttributeError

尝试访问未知的对象属性

为了能够更好的深入理解,我在这举几个例子,展示一下其中几个异常出现的条件和结果:

1.NameError

>>> rocky

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

NameError: name 'rocky' is not defined

在 Python 中虽然不需要在使用变量之前声明类型,但也需要对变量进行赋值,然后才可以使用,不被赋值的变量不能在 Python 中存在,因为变量相当于一个便签,要把它贴到对象上才有意义。

2.IndexError & KeyError

>>> a = [1,2,3]

>>> a[4]

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

IndexError: list index out of range



>>> b = {'name':'rocky'}

>>> b['age']

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

KeyError: 'age'

这两个用我们俗语来说就是「鸡蛋里挑骨头」,一定得报错了,不过在实际编程的时候,特别是循环的时候,常常由于循环条件设置的不合理从而出现这种类型的错误。

3.IOError

>>> f = open('test')

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

FileNotFoundError: [Errno 2] No such file or directory: 'test'

如果你确认有文件,就一定要把路径写正确,因为你并没有告诉 Python 要对你的计算机进行全身搜查,所以 Python 会按照你指定的未知去找,找不到就会出现异常。

这里只是干说其实没有什么效果,具体的还是要在实际编程中碰到才会印象深刻,这里你先把常见的几个记住,到时候别出现问题的时候不知道是什么错误。

当你在运行程序的时候遇到异常时,不要慌张,这个其实是好事情,是 Python 在帮助你修改错误。只要你认真的阅读异常信息,再用我们之前学过的 dir(),help() 或官方文档,搜索工具等来协助,就一定会解决问题。

处理异常

程序出现了异常就要「处理异常」。

首先,让我们先来看一段代码:

while True:

   print('this is a division program.')

   a = input("input 'a' continue,otherwise logout:")

   if a == 'a':

       x = input('first number')

       y = input('second number')

       try:

           print(float(x)/float(y))

           print('***************')

       except ZeroDivisionError:

           print('the second number can not be zero.')

           print('***********************************')



   else:

       break

运行上面的代码,显示的结果如下:

this is a division program.

input 'a' continue,otherwise logout:a

first number5

second number2

2.5

***************

this is a division program.

input 'a' continue,otherwise logout:a

first number5

second number0

the second number can not be zero.

***********************************

this is a division program.

input 'a' continue,otherwise logout:b

从运行的情况来看,当在第 2 个数,即除数为 0 时,程序并没有因为这个错误而停止,而是给了一个很友好的提示,让我们有机会改正错误,这完全得益于「异常处理」的设置,如果没有处理异常的机制,当异常出现的时候程序就会中止。

1.try...except...

对于上面的例子,只看到了 try 和 except 部分,如果没有异常发生的话,except 在 try 执行后被忽略;如果 try 子句中有异常的话,则该部分的其它子句被忽略,直接跳到 except 部分,执行其后面指定的异常类型及其子句。

except 后面也可以没有任何异常类型,即无异常参数。如何这样的话,不论 try 部分发生什么异常,都会执行 except。

2.处理多个异常

try...except... 是处理异常的基本方式,在此基础上,还可以扩展,也就是能够处理多个异常。

这里所说的处理多个异常,并不是因为同时报出多个异常,而是程序在运行中,只要遇到一个异常就会反应,所以每次捕捉到的异常一定是一个,由不同的 except 子句处理。

3. else 子句

其实有了 try...except...,在一般情况下是够用的,但怕就怕在总有不一般的情况出现,所以就增加一个 else 子句,这个其实就和我们说的话一样,总要根据需要添加不少东西。

try:

   print('just try')

except:

   print('just except')

else:

   print('i am else')

上述代码的运行结果如下:

just try

i am else

上述代码能够帮助我们理解 else 的执行特点:如果 try 被执行了,则 except 被忽略,但是 else 被执行。然后我们在来看下面的代码:

try:

   print(1/0)

except:

   print('just except')

else:

   print('i am else')

上述代码的运行结果如下:

just except

这个时候,else 就不被执行了,两个例子帮助我们了解了 else 的执行特点。

4.finally

finally 子句,一看这个名字,就感觉这是做善后工作的。的确如此,如果有了 finally ,不管前面执行的是 try 还是 except,最终都要执行它。因此,有一种说法是将 finally 用在可能的异常后进行清理,请看下面的例子:

x = 10

try:

   x = 1 / 0

except Exception as e:

   print(e)

finally:

   print(e)

   del x

上述代码的运行结果如下:

integer division or modulo by zero

del x

我们来看一看 x 是否被删除:

>>> x

Traceback (most recent call last):

 File "test_search.py", line 1, in <module>

   print(x)

NameError: name 'x' is not defined

当然,在应用里面可以将上面的各个句子综合起来使用,写成下面这样:

try:

   do something

except:

   do something

else:

   do something

finally:

   do something

公众号:程序员喵大人,欢迎来撩