Python异常的排除,以及对Python标准库的基本认知。


异常

错误与异常

如果我们把print拼错为Print,Python会抛出(Raise)一个语法错误。
示例程序块如下:

1
Print("Hello World")

运行结果如下:

1
2
3
4
Traceback (most recent call last):
File "error.py", line 1, in <module>
Print("Hello World")
NameError: name 'Print' is not defined

在上述示例中,NameError错误被抛出,同时Python检测错误发生的位置。这就是一个错误处理器(Error Handler)为我们的错误所做的事情。

处理异常

我们可以通过使用try...except来处理,一般来说,我们把普通的语句放在try代码块中,将我们的错误处理器代码放在except代码块中。

示例程序块如下:

1
2
3
4
5
6
7
8
9
10
11
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))

运行结果如下:

1
2
3
4
5
6
7
8
9
# 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子句可以处理某种特定的错误或者异常,或者是一个在括号中列出的错误或者异常。如果没有提供错误或者异常的名称,那么它将处理所有的错误和异常。

注意:

  1. 必须至少有一句except字句与每一句try字句相关联,否则try代码块无意义。
  2. 若没有任何错误或者异常被处理,那么将调用Python默认处理器,它会利用终端程序打印出错误信息;
  3. else语句与try...except代码块相关联,其作用是再没有发生异常的时候执行。

抛出异常

在Python中,可以通过raise语句来引发一次异常,具体的方法是提供错误名或者异常名以及要抛出(Thrown)异常的对象。
注意:我们能够引发的错误或者异常必须是直接或者间接从属于Exception(异常)类的派生类。

示例程序块如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 wa ' + '{0} long, expected at least {1}').format(ex.length, ex.atleast))
else:
print('No exception was raised.')

运行结果如下:

1
2
3
4
5
6
PS E:\sublime text 3 files\python3> python exceptions_raise.py
Enter something -->a
ShortInputException: The input wa 1 long, expected at least 3
PS E:\sublime text 3 files\python3> python exceptions_raise.py
Enter something -->abc
No exception was raised.

注意:

  1. 在本例中,我们创建了名为ShortInputException的异常类型。它包含两个字段:①获取给定输入文本长度的length ②程序期望的最小长度atleast
  2. except子句中,我们提及了错误类,并将该类存储as为相应的错误名或者异常名。这类似于函数调用中的形参和实参;
  3. 在上述示例中,我们在except子句中使用异常对象的lengthatleast字段来向用户打印一条合适的信息。

Try…Finally

在Python中,我们可以通过finally代码块来确认文件对象是否被正确关闭。

示例程序块如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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) #运行间隔为2s
except IOError:
print("Could not find file poex.txt")
except KeyboardInterrupt:
print("!! You cancelled the reading from the file.")
finally:
if f:
f.close()
print("(Cleaning up: Closed the file)")

运行结果如下:

1
2
3
4
5
6
7
PS E:\sublime text 3 files\python3> python exceptions_finally.py
Programing is fun
Press ctrl+c now
When the work is done
Press ctrl+c now
!! You cancelled the reading from the file.
(Cleaning up: Closed the file)

注意:

  1. 在上例中,我们通过使用time.sleep函数任意在每打印一行后插入两秒的休眠时间;
  2. 在程序运行过程中,通过按下ctrl + c来中断或者取消程序;
  3. 在程序退出之前,finally语句得到执行,文件对象被关闭;
  4. 我们在print之后使用了sys.stout.flush(),以便它能被立即打印到屏幕上。

with语句

在上文中,我们在try块中获取资源,然后再finally块中释放资源是一种常见模式,此外,我们还有一个with语句使得这一过程可以以另一种姿势来完成。

示例程序块如下:

1
2
3
with open("poem.txt") as f:
for line in f:
print(line, end='')

运行结果如下:

1
2
3
4
Programing is fun
When the work is done
if you wanna make your work also fun:
use PYTHON!

注意:

  1. 在此例中,我们使用open函数与with语句,而我们将关闭文件的操作交由with open来完成;
  2. 实际上,with语句使用的协议会获取由open语句返回的对象,再本案例中是thefile
  3. 程序再代码块开始之前调用thefile.__enter__函数,并且总会在代码块执行完后调用thefile.__exit__
  4. 在使用finally代码块中,应该格外留心__exit__方法的自动操作,因为这样可以帮助我们便面重复显式使用try...finally语句。

标准库

Python标准库中包含了大量有用的模块,可以在Python安装包中附带的文档中库概览(Library Reference)部分可以查找到所有模块的全部细节。

sys模块

sys模块中半酣了一些特定系统的功能,下面示例给出其相关用法。

示例运行结果如下:

1
2
3
4
5
6
7
8
PS E:\sublime text 3 files\python3> python
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=6, micro=3, releaselevel='final', serial=0)
>>> sys.version_info.major == 3
True

注意:从上例我们可以看出,sys模块包含一个version_info元祖,它提供给我们版本信息。

日志模块

当我们需要调试(Debugging)程序时,我们可以通过logging模块来实现。

示例程序块如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os
import platform
import logging

if platform.platform().startswith("Windows"):
logging_file = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'), 'test.log')
else:
logging_file = os.path.join(os.getenv('HOME'), 'test.log')

print("Logging to", logging_file)

logging.basicConfig(
level = logging.DEBUG,
format = '%(asctime)s : %(levelname)s : %(message)s',
filename = logging_file,
filemode = 'w',
)

logging.debug("Start of the program")
logging.info("Doing something")
logging.warning("Dying now")

运行结果如下:

1
2
3
4
5
6
PS E:\sublime text 3 files\python3> python stdlib_logging.py
Logging to C:\Users\Administrator\test.log
PS E:\sublime text 3 files\python3> cat C:\Users\Administrator\test.log
2018-04-26 22:57:43,345 : DEBUG : Start of the program
2018-04-26 22:57:43,345 : INFO : Doing something
2018-04-26 22:57:43,345 : WARNING : Dying now

注意:

  1. 上述示例使用了三款标准库中的模块,分别为:①os模块用于和操作系统交互 ②platform模块用于获取我们使用的操作系统的信息 ③logging模块用来记录(Log)信息;
  2. 在示例中,首先通过检查platform.platform()的返回值来确认我们使用的操作系统,如果是Windows,我们就找出来其主驱动器(Home Drive),主文件夹(Home Folder)以及我们希望存储信息的文件名,并将这三个部分汇聚一起,这样我们便得到了此文件的全部位置信息。对其他平台而言,我们只需知道主文件夹位置便可以获得文件的全部位置信息;
  3. 其次,我们使用os.path.join()函数将三部分位置信息聚合到一起;
  4. 再者,我们配置logging模块,从而让它以特定的格式将所有信息写入我们制定的文件内;
  5. 最后不论这些信息时用来调试,提醒或者警告以及其他信息,我们的日志文件test.log都会将其聚合并记录,这样,我们就可以知道自己的程序在运行过程中发生了什么事情。

更多内容,请参考Python Module of the Week或者Python的官方文档