错误

NameError

异常

EOFError:一个文件结尾(End of File)符号(由 ctrl-d 实现)在不该出现的时候出现了。

处理异常

try..except
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))

输出:

# Press ctrl + d
Enter something --> Why did you do an EOF on me?

 # Press ctrl + c
Enter something --> ^CYou cancelled the operation.

Enter something --> No exceptions
You entered No exceptions

如果没有任何错误或异常被处理,那么将调用 Python 默认处理器。
你还可以拥有一个 else 子句与 try..except 代码块相关联。else 子句将在没有发生异常的时候执行。

抛出异常

raise 语句来引发一次异常,具体方法是提供错误名或异常名以及要抛出(Thrown)异常的对象。
你能够引发的错误或异常必须是直接或间接从属于 Exception(异常) 类的派生类。

# 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.')

输出:

Enter something --> 'a'
ShortInputException: The input was 1 long, expected at least 3

Enter something --> 'abc'
No exception was raised.

自定义异常类型ShortInputException

Try … Finally

假设你正在你的读取中读取一份文件。你应该如何确保文件对象被正确关闭,无论是否会发生异常?这可以通过 finally 块来完成。

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)")

输出:

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(),以便它能被立即打印到屏幕上。

with 语句

try 块中获取资源,然后在 finally 块中释放资源是一种常见的模式。因此,还有一个 with 语句使得这一过程可以以一种干净的姿态得以完成。

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 语句。