快乐学习
前程无忧、中华英才非你莫属!

Day8-人生苦短我学python

什么是异常:Python用异常对象(exception object)来表示异常情况.如果异常信息未被处理或捕捉。程序就会用回潄来终止执行

- >>> 1/0

- Traceback (most recent call last):   #Traceback: 一种错误信息

-   File "<stdin>", line 1, in ?
- ZeroDivisionError: integer division or modulo by zero

每个异常都是一些类的实例,这些实例可以被引发,并且可以用很多方式去捕捉,使得程序可以抓住错误并对其进行处理,而不是让整个程序失败.

Note:ZeroDivisionError:就是一个实例

<span style="font-family: SimHei; font-size: 18px;"--<----

按照自己的方式出错

raise语句:

为了引发异常,可以使用一个类或者实例参数调用raise语句。使用类时,程序会自动创建实例,下面是一些简单的例子,使用了内建的Exception异常类

#引发一个没有任何信息的普通异常

- >>> raise Exception
- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
- Exception

#引发一个带错误信息的普通异常

- >>> raise Exception,"This is a normal Exception"

- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
- Exception: This is a normal Exception

#也可以这么写

- >>> raise Exception('System device Busy...')
- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
- Exception: System device Busy...

内建的异常很多,大部分可以再exceptions模块里面找到,可以用dir来列出模块的内容

- >>> dir(exceptions)

- ['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', 'EOFError', 'EnvironmentError', 'Exception', 'FloatingPointError', 'FutureWarning', 'IOError', 'ImportError', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__doc__', '__name__']

Note:

1.所有这些异常都可以用在raise语句中.

2. 最重要的一些内建异常类

<span style="font-family: SimHei; font-size: 18px;"--<----

自定义异常类:

如果内建的异常类不能满足需要,那么就需要独立于exceptions外的异常类,也就是自定义类.

可以添加异常类,像下面的模式

>>> class customerException(Exception): pass

#可以往里面添加方法

<span style="font-family: SimHei; font-size: 18px;"--<----

捕捉异常

异常最有用的地方是能被捕捉,可以用try/except来实现,比如说很两个数相除

- >>> x = input('Enter the first number:')
- Enter the first number:10

- >>> y = input('Enter the second number:')
- Enter the second number:0

- >>> print x/y
- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
- ZeroDivisionError: integer division or modulo by zero.

为了捕捉异常并做出一些处理,可以这样重写程序

- >>> try:
- ...     x = input('Enter the 1st number:')
- ...     y = input('Enter the 2nd number:')
-         print x/y
- ... except ZeroDivisionError:
- ...     print "The second number can't be zero!"

- ...
- Enter the 1st number:10

- Enter the 2nd number:0

- The second number can't be zero!

Note: 如果没有捕捉异常,它就会被传播到调用它的函数中,如果依然没有捕获,这些异常就会浮到程序的最顶层,

也就是说你可以捕捉到在其他人的函数所引发的异常。

<span style="font-family: SimHei; font-size: 18px;"--<----

看,没有参数

如果捕捉到异常,又想重新引发它,那么就可以调用不带参数的raise,举个例子吧,看这么做,多有用!考虑一个能屏蔽ZeroDivisionError的计算器类,如果这个错误被激活,计算器就会打印出错误,而不是让异常传播,如果这是在用户交互的过程中使用,这就非常有用,但是,如果在程序内部使用,引发异常会更好些,那么屏蔽机制就可以关掉。下面是这样一个类的代码

- class MuffledCalculator:
-     muffled = False

-     def cal(self,expr):
-         try:
-             return eval(expr)
-         except ZeroDivisionError:
-             if self.muffled:
-                 print 'Division by zero is illegal'

-             else:
-                 raise

输出结果

- >>> c = MuffledCalculator()
- >>> c.cal('10/2')
- 5

- >>> c.cal('10/0')
- Traceback (most recent call last):
-   File "<pyshell#2>", line 1, in <module>
-     c.cal('10/0')
-   File "D:\Learn\Python\Exception.py", line 13, in cal
-     return eval(expr)
-   File "<string>", line 1, in <module>
- ZeroDivisionError: integer division or modulo by zero
- >>> c.muffled = True

- >>> c.cal('10/0')
- Division by zero is illegal

<span style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); font-family: SimHei; font-size: 18px;"--<----

多个except语句

- >>> x = input('Enter the 1st number:')
- Enter the 1st number:10

- >>> y = input('Enter the 2nd number:')
- Enter the 2nd number:'hello,world!'

- >>>
- >>> print x/y
- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
- TypeError: unsupported operand type(s) for /: 'int' and 'str'

那么应该这么写:

- try:
-     x = input('Enter the 1st number:')
-     y = input('Enter the 2nd number:')
-     print x/y
- except ZeroDivisionError:
-     print "The second number can't be zero!"

- except TypeError:
-     print "That wasn't a number, was it?"

<span style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); font-family: SimHei; font-size: 18px;"--<----

用一个快来捕捉多个异常

- try:
-     x = input('Enter the 1st number:')
-     y = input('Enter the 2nd number:')
-     print x/y
- #拿所有可能的错误,放在元祖里面,

- #注意,一定要用(),否则可能出现不可预知的错误

- except (ZeroDivisionError,TypeError,NameError):
-     print "Your numbers were bogus..."

<span style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); font-family: SimHei; font-size: 18px;"--<----

捕捉对象

如果希望在except子句中访问异常对象本身,可以使用两个参数。比如,如果想让程序继续运行,但是又因为某种原因想记录下错误(比如只是打印给用户看),这个功能就很有用。下面的例子可以打印异常,但程序会继续运行。

- try:
-     x = input('Enter the 1st number:')
-     y = input('Enter the 2nd number:')
-     print x/y
- except (ZeroDivisionError,TypeError,NameError), e:
-     print e
- print 'Hello,World!'

输出结果:

- >>>
- Enter the 1st number:10

- Enter the 2nd number:0

- integer division or modulo by zero
- 'Hello,World!'

- >>>
- Enter the 1st number:10

- Enter the 2nd number:hello
- name 'hello' is not defined
- 'Hello,World!'

Note: Python3.0中表示方式是except (ZeroDivisionError,TypeError,NameError) as e

<span style="font-family: SimHei; font-size: 18px;"--<----

真正的全捕捉:

就算程序能处理好几个异常,但有些异常还是会从眼皮底下溜走,还是刚才那个除法的程序,如果什么都不输入呢? 

- Traceback (most recent call last):
-   File "<pyshell#0>", line 2, in <module>
-     x = input('Enter the 1st number:')
-   File "<string>", line 0

-

-    ^
- SyntaxError: unexpected EOF while parsing

这个异常逃过了try/except,而且程序员也不可能预测所有可能的异常,因此不能捕获所有异常,如果想让程序捕获所有异常,可以这样写:

- try:
-     x = input('Enter the 1st number:')
-     y = input('Enter the 2nd number:')
-     print x/y
- except:
-     print "Something Wrong Happen!"
  1.  

这样就可以捕获所有异常

WRAN: 像这样捕捉所有异常是危险的,因为它会隐藏所有程序员未想到并且未做好准备处理的错误。它同样会捕捉用户终止执行CTRL+C企图,以及用sys.exit函数终止程序的企图,等等。这是用except Exception,e会更好些,或者对异常对象e进行一些检查。

<span style="font-family: SimHei; font-size: 18px;"--<----

万事大吉:

有些时候一些坏事发生时执行一段代码会很有用,这时候可以像条件,循环一样,加个else语句

- >>> try:
- ...     print "A Simple"

- ... except:
- ...     print "What? Something went wrong?"

- ... else:
- ...     print "Ah...Runing as planed."

- ...
- A Simple
- Ah...Runing as planed.
  1.  

使用else子句可以实现之前提到的循环

- while True:
-     try:
-         x = input('Enter 1st number:')
-         y = input('Enter 2nd number:')
-         value = x/y
-         print 'x/y is:', value
-     except:
-         print 'Invalid input, please try again!'

-     else:
-         break

输出结果:

- >>>
- Enter 1st number:10

- Enter 2nd number:0

- Invalid input, please try again!
- Enter 1st number:10

- Enter 2nd number:e
- Invalid input, please try again!
- Enter 1st number:10

- Enter 2nd number:2

- x/y is: 5

考虑到捕捉全部的异常有风险,可以用Exception,e来替代,并打印错误信息,程序再改进下:

- while True:
-     try:
-         x = input('Enter 1st number:')
-         y = input('Enter 2nd number:')
-         value = x/y
-         print 'x/y is:', value
-     except Exception, e:
-         print 'Invalid input', e
-         print 'please try again!'

-     else:
-         break

输出结果:

- Enter 1st number:10

- Enter 2nd number:0

- Invalid input integer division or modulo by zero
- please try again!
- Enter 1st number:10

- Enter 2nd number:hello
- Invalid input name 'hello' is not defined
- please try again!
- Enter 1st number:10

- Enter 2nd number:2

- x/y is: 5

<span style="font-family: SimHei; font-size: 18px;"--<----

最后

最后是finally子句,她可以用在可能的异常清理,也可以用在关闭数据库链接,关闭文件句柄等。一般是try/finally联合使用

- x = None

- try:
-     x = 1/0

- finally:
-     print "Cleaning Up..."

-     del x

上面的代码中,finally子句肯定会被执行,不管try子句中是否发生异常(在try子句之前初始化x的原因是如果不这样做,由于ZeroDivisionError的存在,x就永远不会被赋值。这样就会导致在finally子句中使用del删除它的时候产生异常,而且这个异常是无法捕捉的)运行这段代码,在程序崩溃之前,对于变量x的清理就完成了。

输出结果:

- >>>
- Cleaning Up...
-

- Traceback (most recent call last):
-   File "D:\Learn\Python\Exception.py", line 72, in <module>
-     x = 1/0

- ZeroDivisionError: integer division or modulo by zero

因为使用del删除一个变量时很不负责的清理手段,所以finally子句用于关闭数据库链接,关闭文件句柄会非常有用。也可以try,except,else,finally联合使用(或者至少使用其中3个)

- try:
-     1/0

- except Exception, e:
-     print e
- else:
-     print "That's well well."

- finally:
-     print "Clean Up..."

输出结果:

- >>>
- integer division or modulo by zero
- Clean Up...

<span style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); font-family: SimHei; font-size: 18px;"--<----

异常和函数

异常和函数能很自然的工作。如果异常在函数内引发而不被处理,她就会传播至函数调用的地方。如果在哪里也没有处理异常,她会继续传播,一直到达主程序。如果那里也没有异常处理程序,程序会带着堆栈跟踪终止。

- >>> def faulty():
- ...     raise Exception('Something is wrong.')
- ...
- >>> def ignore_exception():
- ...     faulty()
- ...
- >>> def handle_exception():
- ...     try:
- ...         faulty()
- ...     except:
- ...         print 'Exception handled'

- ...

输出结果:

- >>> ignore_exception()
- Traceback (most recent call last):
-   File "<stdin>", line 1, in ?
-   File "<stdin>", line 2, in ignore_exception
-   File "<stdin>", line 2, in faulty
- Exception: Something is wrong.
- >>> handle_exception()
- Exception handled

可以看出,faulty()产生的异常通过faulty和ignore_exception()传播,最终导致了堆栈跟踪。

同样的,她也传播到了handle_exception(),但是也个函数被try/except处理了。

<span style="font-family: SimHei; font-size: 18px;"--<----

异常之禅

有些时候if/else实现会比try/except实现起来更好,让我们看看下面几个例子:

- def describePerson(person):
-     print 'Description of',person['name']
-     print 'Age:', person['age']
-     if 'occupation' in person:
-         print 'Occupation:',person['occupation']
- >>> d = {'name':'Alice','age':28}
- >>> describePerson(d)
- Description of Alice
- Age: 28

- >>> d = {'name':'Alice','age':28,'occupation':'IT'}
- >>> describePerson(d)
- Description of Alice
- Age: 28

- Occupation: IT

代码非常直观,但是效率不高,程序会两次查找occupation

一次是查看键是否存在,另外一次是获取值

- def describePerson(person):
-     print 'Description of',person['name']
-     print 'Age:', person['age']
-     try:
-         print 'Occupation:'+ person['occupation']
-     except KeyError:
-         pass

NOTE:这里打印职业时用的是+,而不是,否则字符串在引发异常时就会被输出。这样写直接假定occupation已经存在,如果不存在的话,在except KeyError中捕获.从而提高了程序的效率.在查看对象是否存在特定值时,try/except也很有用

- try:
-     obj.write
- except AttributeError:
-     print 'The object is not writeable'

- else:
-     print 'The object is writeable.'
  1.   

<span style="color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); font-family: SimHei; font-size: 18px;"--<----

本章函数

warning.filterwarnings(action)             用于过滤警告

打赏
赞(0) 打赏
未经允许不得转载:同乐学堂 » Day8-人生苦短我学python

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

error: Sorry,暂时内容不可复制!