Python入门基础第十六课--异常处理

1.前言

    经历了一段论文的挣扎以后,我胡汉三又回来了。还是好汉一条,接着上次的面向对象的话题,本章来介绍一个简单的话题--异常处理。编写程序完成后,我们需要编译和连接,在这个编译器会给我们抛出一些错误和异常,我们通常会将这些错误和异常分类。再去具体的程序里面检查到底是哪里出现了错误。

  一般常见的处理方式是:我们在可能会发生错误和异常的地方用条件语句先去判断,但是这样的做法只是暂时的。假如你的程序设计的很庞大、结构很复杂。条件语句的多次出现会让程序很不灵活,而且会加大程序阅读的难度。那么,我们应该怎样处理呢?一起来看看。

2.异常是啥?

  Python用异常对象来表示异常对象,当遇到错误后,会引发异常。如果这个异常没有被处理,那么就会回溯终止执行。来看看一个具体的列子:

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

  我们知道,在除法运算分母当然不能是0了,这时候Python就会抛出一个异常。ZeroDivisionError:division by zero。其实,每个异常都是一些类,在这个例子里面我们看到就是ZeroDivisionError的实例。这些例子可以被引发,并且可以通过多种方式和方法,并不仅仅限于1/0这个例子。这样的异常可以让程序可以捕捉到这样的错误并及时的处理它,而不是说一旦发生这个错误就让整个程序崩溃!

3.异常详述

3.1属于自己的简单异常

    处于人性化和易读性的考虑,Python内建了许多的异常类,我们可以使用raise语句和内建异常中的Exception来设置属于自己的异常提示语句。来看看下面的例子。

>>> raise Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception
>>> raise Exception("America is small than China")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: America is small than China

  在上面的例子中,起初我们并没有给定异常提醒语句,只是简单出发一个异常。第二次的时候,我们利用提示语句"America is small than China",果不其然,这样的提示被打印出来了。这样的方式提示着我们:在你不确定哪里有异常的时候,最好采用下面即将说道的异常处理方法,并设置好合适的提示语,这样程序设计出来才是合格的。By the Way,给大家一些Python内建的异常。

类名 描述
Exception 所有异常的基类
AttributeError 特性引用或者赋值失败时候引发
IOError 试图打开不存在文件时候引发
IndexError 在序列中引用不存在的索引时候引发
KeyError 在使用映射中不存在的键的时候引发
NameError 找不到名字(变量)时候引发
SyntanxError 代码形式错误时候引发
TypeError 内建操作或者函数应用于错误类型的对象时候引发
ValueError 在内建操作或者函数应用于正确类型的对象,但是该对象使用不适合的值时候引发
ZeroDivisionError 在除法或者模除操作第二个数为0 的时候引发

3.2捕捉异常并处理

  在这部分,我们直接来看一个例子,会比较容易懂得异常处理的方法。

class MufflesCalculator:
    muffled=False
    def calc(self,expr):
        try:
            return eval(expr)
        except ZeroDivisionError:
            if self.muffled:
                print 'Division by Zero is illegal'
            else:
                raise

calculator=MufflesCalculator()
print calculator.calc('10/2')
print calculator.calc('10/0')
/usr/local/bin/python2.7 /Users/yangjiayuan/PycharmProjects/day/day15/the_use_of_except.py
5
Traceback (most recent call last):
  File "/Users/yangjiayuan/PycharmProjects/day/day15/the_use_of_except.py", line 16, in <module>
    print calculator.calc('10/0')
  File "/Users/yangjiayuan/PycharmProjects/day/day15/the_use_of_except.py", line 7, in calc
    return eval(expr)
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Process finished with exit code 1

  看一看上面的运行结果,正常的分母理所当然得到的结果是正确的。但是当我们将分母改为0的时候,编译器报错了,虽然这个异常被捕捉到了但是并没有被“屏蔽”,而且已经被传递了。这是由于我们没有将屏蔽机制打开。再来看看下面这样的处理结果

class MufflesCalculator:
    muffled=True
    def calc(self,expr):
        try:
            return eval(expr)
        except ZeroDivisionError:
            if self.muffled:
                print 'Division by Zero is illegal'
            else:
                raise

calculator=MufflesCalculator()
print calculator.calc('10/2')
print calculator.calc('10/0')
/usr/local/bin/python2.7 /Users/yangjiayuan/PycharmProjects/day/day15/the_use_of_except.py
5
Division by Zero is illegal
None


Process finished with exit code 0

  现在的结果是不是和上面的不一样了,注意看红色字体的部分和上面程序里的对比。这也是我们打开了“屏蔽”机制。屏蔽掉这样的异常,也就是不让异常传递下去。有人很奇怪为什么我将调用两次函数的运行结果打印出来,最后会出现一个None。如果除零行为发生,而且屏蔽机制打开的话,calc方法会隐式的返回一个None。如果屏蔽机制是开的,那么久不应依赖返回值。再来看看下面这样的写法。

def Validate(name,pwd):
    if name=='alex' and pwd=='123':
        return True
    else:
        return False

try:
    res=Validate('alex','456')
    if res:
        print 'sucess login'
    else:
        raise Exception('failure login')
except Exception,e:
    print 'code in database'
    print e

     还是注意红色字体标注的位置,如果你想再except语句中访问异常对象本身,可以使用两个参数,就算你想捕捉多个异常也只需要向except子句提供一个参数,一个元组。就像上面的写法一样。这是在Python2.x里面的写法,在Python3中会写成这个样子:except Exception as e。使用不同的编译器环境的话需要注意到这一点。讲到这里,我们再来看看下面的处理方式。

while True:
    try:
        x=int(raw_input('Enter the first number: '))
        y=int(raw_input('Enter the second number: '))
        value=x/y
        print 'x/y is', value
    except:
        print 'Invaild input,Please try again'
    else:
        break
/usr/local/bin/python2.7 /Users/yangjiayuan/PycharmProjects/day/day15/the_use_of_except.py
Enter the first number: 100
Enter the second number: 0
Invaild input,Please try again
Enter the first number: 8
Enter the second number: lalala
Invaild input,Please try again
Enter the first number: 9
Enter the second number: hahaha
Invaild input,Please try again
Enter the first number: 1000
Enter the second number: 10
x/y is 100

Process finished with exit code 0

    上面的这个程序做了进一步的改进,else语句出现了。循环只有在没有发生异常的时候才会跳出。仔细体会一个else在这里的作用。还有,你可以尝试将这里的异常捕捉方式换为except Exception,e这样的方式会更好!最后来看的例子很简单。

try:
    1/0
except ZeroDivisionError:
    print "Unknow variable."
else:
    print "That went well."
finally:
    print "Cleaning up."
try:
    1/1
except ZeroDivisionError:
    print "Unknow variable."
else:
    print "That went well."
finally:
    print "Cleaning up."

    自己运行以下上面这两段代码,看看有什么结果。特别是关注finally语句的结果。

    异常并不是很复杂。如果知道某段代码可能会导致某种异常,而又不希望程序以堆栈跟踪的形式终止,那么久根据需要天剑try/except或者try/finally语句进行处理。尽量不要使用if/else语句来代替try/except语句。很多情况下这样并不会提高效率。好了,异常的有关内容就讲到这里,下一章节预告--方法、属性、迭代器。



猜你喜欢

转载自blog.csdn.net/qq_34454366/article/details/80382539