当你的程序出现例外状况时就会发生异常(Exception)。例如,当你想要读取一个文件时,而那个文件却不存在,怎么办?又或者你在程序执行时不当心把它删除了,怎么办?这些经过使用异常来进行处理。html
相似地,若是你的程序中出现了一些无效的语句该怎么办?Python 将会对此进行处理,举起(Raises)它的小手来告诉你哪里出现了一个错误(Error)。python
你能够想象一个简单的 print 函数调用。若是咱们把 print 误拼成 Print 会怎样?你会注意到它的首字母是大写。在这一例子中,Python 会抛出(Raise)一个语法错误。函数
>>> Print("Hello World") Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'Print' is not defined >>> print("Hello World") Hello World
你会注意到一个 NameError 错误被抛出,同时 Python 还会打印出检测到的错误发生的位置。这就是一个错误错误处理器(Error Handler)2 为这个错误所作的事情。spa
咱们将尝试(Try)去读取用户的输入内容。按下 [ctrl-d] 来看看会发生什么事情。code
>>> s = input('Enter something --> ') Enter something --> Traceback (most recent call last): File "<stdin>", line 1, in <module> EOFError
此处 Python 指出了一个称做 EOFError 的错误,表明着它发现了一个文件结尾(End of File)符号(由 ctrl-d 实现)在不应出现的时候出现了。orm
咱们能够经过使用 try..except 来处理异常情况。通常来讲咱们会把一般的语句放在 try 代码块中,将咱们的错误处理器代码放置在 except 代码块中。htm
案例(保存文 exceptions_handle.py):对象
try: text = input('Enter something --> ') except EOFError: print('Why did you do an EOF on me?') except KeyboardInterrupt: print('You cancelled the operation.') else: print('You entered {}'.format(text))
输出:blog
# Press ctrl + d $ python exceptions_handle.py Enter something --> Why did you do an EOF on me? # Press ctrl + c $ python exceptions_handle.py Enter something --> ^CYou cancelled the operation. $ python exceptions_handle.py Enter something --> No exceptions You entered No exceptions
它是如何工做的教程
咱们将全部可能引起异常或错误的语句放在 try 代码块中,并将相应的错误或异常的处理器(Handler)放在 except 子句或代码块中。except 子句能够处理某种特定的错误或异常,或者是一个在括号中列出的错误或异常。若是没有提供错误或异常的名称,它将处理全部错误与异常。
要注意到必须至少有一句 except 字句与每一句 try 字句相关联。否则,有一个 try 代码块又有什么意义?
若是没有任何错误或异常被处理,那么将调用 Python 默认处理器,它只会终端程序执行并打印出错误信息。咱们已经在前面的章节里见过了这种处理方式。
你还能够拥有一个 else 子句与 try..except 代码块相关联。else 子句将在没有发生异常的时候执行。
在下一个案例中,咱们还将了解如何获取异常对象以便咱们能够检索其余信息。
你能够经过 raise 语句来引起一次异常,具体方法是提供错误名或异常名以及要抛出(Thrown)异常的对象。
你可以引起的错误或异常必须是直接或间接从属于 Exception(异常) 类的python 派生类。
案例(保存为 exceptions_raise.py):
# encoding=UTF-8 class ShortInputException(Exception): '''一个由用户定义的异常类''' def __init__(self, length, atleast): Exception.__init__(self) self.length = length self.atleast = atleast try: text = input('Enter something --> ') if len(text) < 3: raise ShortInputException(len(text), 3) # 其余工做能在此处继续正常运行 except EOFError: print('Why did you do an EOF on me?') except ShortInputException as ex: print(('ShortInputException: The input was ' + '{0} long, expected at least {1}') .format(ex.length, ex.atleast)) else: print('No exception was raised.')
输出:
$ python exceptions_raise.py Enter something --> a ShortInputException: The input was 1 long, expected at least 3 $ python exceptions_raise.py Enter something --> abc No exception was raised.
它是如何工做的
在本例中,咱们建立了咱们本身的异常类型。这一新的异常类型叫做 ShortInputException。它包含两个字段——获取给定输入文本长度的 length,程序指望的最小长度 atleast。
在 except 子句中,咱们说起了错误类,将该类存储 as(为) 相应的错误名或异常名。这相似于函数调用中的形参与实参。在这个特殊的 except 子句中咱们使用异常对象的 length 与 atleast 字段来向用户打印一条合适的信息。
假设你正在你的读取中读取一份文件。你应该如何确保文件对象被正确关闭,不管是否会发生异常?这能够经过 finally 块来完成。
保存该程序为 exceptions_finally.py:
import sys import time f = None try: f = open("poem.txt") # 咱们经常使用的文件阅读风格 while True: line = f.readline() if len(line) == 0: break print(line, end='') sys.stdout.flush() print("Press ctrl+c now") # 为了确保它能运行一段时间 time.sleep(2) except IOError: print("Could not find file poem.txt") except KeyboardInterrupt: print("!! You cancelled the reading from the file.") finally: if f: f.close() print("(Cleaning up: Closed the file)")
输出:
$ python exceptions_finally.py Programming is fun Press ctrl+c now ^C!! You cancelled the reading from the file. (Cleaning up: Closed the file)
它是如何工做的
咱们按照一般文件读取进行操做,可是咱们同时经过使用 time.sleep 函数任意在每打印一行后插入两秒休眠,使得程序运行变得缓慢(在一般状况下 Python 运行得很是快速)。当程序在处在运行过过程当中时,按下 ctrl + c 来中断或取消程序。
你会注意到 KeyboardInterrupt 异常被抛出,尔后程序退出。不过,在程序退出以前,finally 子句获得执行,文件对象总会被关闭。
另外要注意到咱们在 print 以后使用了 sys.stout.flush(),以便它能被当即打印到屏幕上。
在 try 块中获取资源,而后在 finally 块中释放资源是一种常见的模式。所以,还有一个 with 语句使得这一过程能够以一种干净的姿态得以完成。
保存为 exceptions_using_with.py:
with open("poem.txt") as f: for line in f: print(line, end='')
它是如何工做的
程序输出的内容应与上一个案例所呈现的相同。本例的不一样之处在于咱们使用的是 open 函数与 with 语句——咱们将关闭文件的操做交由 with open 来自动完成。
在幕后发生的事情是有一项 with 语句所使用的协议(Protocol)。它会获取由 open 语句返回的对象,在本案例中就是“thefile”。
它总会在代码块开始以前调用 thefile.__enter__ 函数,而且总会在代码块执行完毕以后调用 thefile.__exit__。
所以,咱们在 finally 代码块中编写的代码应该格外留心 __exit__ 方法的自动操做。这可以帮助咱们避免重复显式使用 try..finally 语句。
有关Python教程中这话题的更多讨论已经超出了本书所能涉及的范围,所以请参考 PEP 343 来了解更加全面的解释。
咱们已经讨论了 try..except 和 try..finally 语句的用法。同时咱们也已经看到了如何建立咱们本身的python 异常类型,还有如何抛出异常。
接下来,咱们将探索 Python 的标准库。