异常(Exceptions)是什么
Python 使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让 Python 不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异常的代码,程序将继续运行;如果你未对异常进行处理,程序将停止,并显示一个 traceback ,其中包含有关异常的报告。
除零错误ZeroDivisionError: division by zero
1/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-2-9e1622b385b6> in <module>
----> 1 1/0
ZeroDivisionError: division by zero
事实上,异常不仅能用来显示错误信息,它还是某个类的实例(这里是ZeroDivisionError)。程序员可以各种方式引发和捕获这些实例,从而采取措施修改程序。
命名错误NameError: name ‘ok’ is not defined
ok
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-92a949fd4184> in <module>
----> 1 ok
NameError: name 'ok' is not defined
类型错误TypeError
2 + '2'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-82150feed70c> in <module>
----> 1 2 + '2'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
python标准异常
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 好像是读取异常 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
处理异常(try…except…)
处理异常的目的
当你知道你的代码可能会产生某种异常, 但是你却不希望, 当这种异常出现的时候导致程序终止, 你想要让程序即使出现了异常也能跳过去继续向下运行, 这时候你就需要添加try/except 或try/finally语句来处理它。
假设创建了一个程序,让用户输入两个数,再将它们相除,如下所示:
x = int(input('Enter the first number:'))
y = int(input('Enter the second number:'))
print(x/y)
Enter the first number:1
Enter the second number:2
0.5
为捕获这种异常,并对错误进行处理,这里只输出一条对用户的错误信息,可以重写程序如下:
try:
x = int(input('Enter the first number'))
y = int(input('Enter the second number'))
print(x/y)
except ZeroDivisionError:
print("The second number can't be zero!")
Enter the first number5
Enter the second number0
The second number can't be zero!
def f(a, b):
if b == 0:
return "您的输入有错误, 分母不能为0, 请重新输入!"
return a/b
我们可能会自然的使用条件判断语句来完成异常处理的目标, 但这样编写出来的代码, 没有使用try/except的可读性那么高。
def f1(a, b):
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
return a / b
except: # 当try里面的代码有问题的时候, 则跳到except里面去运行
return '您有输入错误, 分母不能为0'
可以通过指定错误类型的方法, 让try语句只捕捉指定异常类型
def f2(a, b, c):
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
return a / (b+c)
except TypeError as e: # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('您的错误信息是:', e)
f2(1,3,'a')
您的错误信息是: unsupported operand type(s) for +: 'int' and 'str'
f2(1,0,0)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-9-3e105ee556ce> in <module>
----> 1 f2(1,0,0)
<ipython-input-7-adf24eadb550> in f2(a, b, c)
1 def f2(a, b, c):
2 try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
----> 3 return a / (b+c)
4 except TypeError as e: # 当try里面的代码有问题的时候, 则跳到except里面去运行
5 print('您的错误信息是:', e)
ZeroDivisionError: division by zero
这时可以设置多个except语句捕捉多个异常
错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。可以有多个except来捕获不同类型的错误:
def f3(a, b, c):
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
return a / (b+c)
except TypeError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('TypeError:', e)
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('ZeroDivisionError:', e)
f3(4,0,0)
ZeroDivisionError: division by zero
f3(2, 0, '5')
TypeError: unsupported operand type(s) for +: 'int' and 'str'
我们也可以把多个错误类型同时放入到一个except语句中进行捕获
def f4(a, b, c, d):
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
x = b + c
y = d[3]
z = a/b
return x, y, z
except (TypeError,ZeroDivisionError, IndexError ) as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('您的错误信息是:', e)
f4(1, 0, 2,[1, 2, 3, 4])
您的错误信息是: division by zero
f4(1, 3, 'a',[1, 2, 3, 4])
您的错误信息是: unsupported operand type(s) for +: 'int' and 'str'
f4(1, 3, 5,[1, 2])
您的错误信息是: list index out of range
finally和else的使用
当我们认为某些代码可能会出错时,就可以用try来运行这段代码,
如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。
try-except-else
代码块的工作原理:
Python会先尝试执行try代码块中的代码;只有可能引发异常的代码才有必要放到try语句中。有时,有一些代码只有在try代码块执行没问题时才需要执行,这些代码我们把它放到else代码块中。except代码块在try执行时引发了异常才会执行。
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
print( 10 / 2 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('ZeroDivisionError:', e)
else:
print('else里面的代码')
5.0
else里面的代码
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
print( 10 / 0 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('ZeroDivisionError:', e)
else:
print('else里面的代码')
ZeroDivisionError: division by zero
finally子句
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
print( 10 / 2 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('ZeroDivisionError:', e)
finally:
print('finally里面的代码')
5.0
finally里面的代码
try: # 先尝试运行try内部的代码, 如果正常运行则和没写一样
print( 10 / 0 )
except ZeroDivisionError as e : # 当try里面的代码有问题的时候, 则跳到except里面去运行
print('ZeroDivisionError:', e)
finally:
print('finally里面的代码')
ZeroDivisionError: division by zero
finally里面的代码
上述示例,不管try子句发生什么异常,都将执行finally子句。可用于在发生异常时执行清理工作,这个子句是与try子句配套的。
try:
1 / 0
except NameError:
print("Unknown variable")
else:
print("That went well!")
finally:
print("Cleaning up.")
Cleaning up.
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-15-38d8b6ee80bd> in <module>
1 try:
----> 2 1 / 0
3 except NameError:
4 print("Unknown variable")
5 else:
ZeroDivisionError: division by zero
try:
x = 1 / 1
except NameError:
print("Unknown variable")
else:
print("That went well!")
finally:
print("Cleaning up.")
del x
That went well!
Cleaning up.
捕获到异常时,如果不想吭气,可以用pass语句。
def readandprint(filename):
"""读取文件内容打印出来"""
try:
with open(filename) as f:
contents = f.read()
except FileNotFoundError:
#print(filename+" 不存在.")
pass
else:
print(contents)
readandprint("1s.txt")
with open("PrideandPrejudice.txt",encoding="UTF-8") as f:
contents = f.read()
words = contents.split()
num_words = len(words) #总单词数
print(num_words)
feq = contents.count("Mary") #统计 Mary 出现的次数.
print(feq)
124706
39
参考文献:Python编程从入门到实践/(美)埃里克 马瑟斯(Eric Matthes)著;袁国忠译.–北京:人民邮电出版社,2016,7