一.python中的错误与异常。
先来说说什么是错误。
在python中错误分为两种
-
语法错误这种语法错误根本过不了python解释器下面这几种就属于语法错误。
例1:
if
输出
File "/Users/macbook/PycharmProjects/untitled1/作业2/test2.py", line 1
if
^
SyntaxError: invalid syntax
例2:
def test:
pass
例3:
class Foo
pass
以上这些都是语法错误
2 . 逻辑错误
#用户输入不完整(比如输入为空)或者输入非法(输入不是数字)
num=input(">>: ")
int(num)
# 无法完成计算
res1=1/0
res2=1+'str'
接着在来说说什么是异常
所谓的异常就是程序运行时发出的错误信号。
首先我们在python解释器中输入一个解释无法识别的内容。
>>>asdkjsdkjhaslk
结果就是抛出一个异常
Traceback (most recent call last): #Traceback 是异常的追踪信息
File "/tmp/test2.py", line 2, in <module>
asdkjsdkjhaslk
NameError: name 'asdkjsdkjhaslk' is not defined
NameError 是异常的类。
name 'asdkjsdkjhaslk' is not defined 这个就是异常的值。
所以当解释器抛出一个异常信息时这个异常大概由三部分组成
-
追踪信息。
-
异常类名。
-
异常值。
二.python中自带的常见异常类。
AttributeError 试图访问一个对象没有的树形比如foo.x但是foo没有属性x
IOError 输入/输出异常基本上是无法打开文件
ImportError 无法引入模块或包基本上是路径问题或名称错误
IndentationError 语法错误的子类 代码没有正确对齐
IndexError 下标索引超出序列边界比如当x只有三个元素却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法代码不能编译(个人认为这是语法错误写错了
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量基本上是由于另有一个同名的全局变量
导致你以为正在访问它
ValueError 传入一个调用者不期望的值即使值的类型是正确的
注意这些只是python内部异常类中比较常见的一些并不是全部
三.异常处理
-
什么是异常处理
第一种当python解释器检测到程序有错误就会触发一个异常当然程序员也可以使用raise手动去触发一个异常。也就是说程序执行到了一个程序员不想要的一个结果就可以手动的使用raise去触发一个异常让程序终止。
第二种程序员编写特定的代码用来捕捉一个异常。也就是说程序的某一步会触发一个异常异常一旦触发整个python程序就会终止当程序员不想让这个异常被触发可以使用try 和 except捕捉这个异常将其忽略假设当异常被触发后程序依然可以正常运行。
当异常捕捉成功后会进入另外一个处理分支执行你为其定制的逻辑使程序不会崩溃这就是异常处理。
2.如何去进行异常处理
在处理异常之前有两点是必须清楚的
第一点程序的异常是由错误引起的。
第二点语法上的错误与异常处理没关系这种语法上的错误必须在程序运行前修正
2.1 使用if判断去处理异常
首先我们可以先来运行下面这段代码。
# -*- coding:utf-8 -*-
#第一段代码
num1=raw_input('>>: ') #输入一个字符串试试
int(num1)
#第二段代码
num2=raw_input('>>: ') #输入一个字符串试试
int(num2)
#第三段代码
num3=raw_input('>>: ') #输入一个字符串试试
int(num3)
执行了上面这段代码会触发一个ValueError的异常一旦异常被触发程序就会退出后面的 代码都不会被执行了。
接下来使用if判断去处理这个异常
# -*- coding:utf-8 -*-
num1=raw_input('>>: ') #输入一个字符串试试
if num1.isdigit():
int(num1) #我们的正统程序放到了这里,其余的都属于异常处理范畴
elif num1.isspace():
print '输入的是空格,就执行我这里的代码'
elif len(num1) == 0:
print '输入的是空,就执行我这里的逻辑代码'
else:
print '其他情情况,执行我这里的逻辑代码'
既然if判断可以去处理异常那么为什么几乎没人使用if判断去处理异常呢
使用if的方式我们只为第一段代码加上了异常处理针对第二段代码你得重新写一堆ifelif等...
当然也可以把合并到一块去写但是你会发现代码的可读性变的非常非常的差
注意在使用if判断去处理异常时会碰到一个更恶心的问题就拿上面那个例子来举例吧第一 段代码和第二段代码碰到的都是同一种异常都是ValueError,按照正常的思维去想相同的错 误处理一次就可以了但是如果使用了if判断两段代码的if判断条件不同只能逼着你重新在 写一个新的if判断去处理第二段代码的异常。。。第三段。。。第四段。。。第五段。。。周而复 始。。。处理异常的代码你就慢慢写吧。。。。
2.2 使用python专门处理异常的机制来处理异常。
其实在python内部为每一种异常定制了一个专门的异常类也可以理解为异常的类型然后 提供了一种特定的语法结构来专门处理异常。
这种语法结构就是try和except基本的语法结构如下
try:
被检测的代码块
except 异常类型
try中一旦检测到异常就执行这个位置的逻辑
知道了基本语法接下来来看一个处理异常的例子
下面这个代码如果没有处理异常的话直接就会抛出异常。
s1 = 'hello'
try:
int(s1)
except IndexError as e: 解释下后面的as关键字except如果捕捉到了IndexError这个异常将异常的value直接赋给
print e 变量e
2.3 同时捕获多种异常多分支捕获异常
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
2.4 万能异常。
在python的异常中有一个万能异常Exception他可以捕获任意异常。
示例
s1 = 'hello'
try:
int(s1)
except Exception as e:
print(e)
四.分析万能异常与多分枝异常的应用场景。
情况一如果你想要的效果是无论出现什么异常我们统一丢弃或者使用同一段代码逻辑去处理他们那么这个时候用Exception(万能异常类)是个很好的选择。
例1
s1 = 'hello'
try:
int(s1)
except Exception,e:
'丢弃或者执行其他逻辑'
print e
#如果你统一用Exception没错是可以捕捉所有异常但意味着你在处理所有异常时都使用同一个逻辑去处理这里说的逻辑即当前expect下面跟的代码块
情况二如果你想要的效果是对于不同的异常我们需要定制不同的处理逻辑那就需要用到多分支了。
例2
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print e
except KeyError as e:
print e
except ValueError as e:
print e
多分支异常处理还可以和万能异常同时使用
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print e
except KeyError as e:
print e
except ValueError as e:
print e
except Exception as e: 这里是万能异常
print e
五.try异常捕捉的其它结构介绍。
python的try代码块还有两个知识点没有介绍就是try代码块的else分支和finally分支。
当try中的代码块中没有任何异常时else分支下的代码就会被执行。
而finally中的代码块的执行条件是无论try中代码块的代码执行是否有异常到了最后都会被执行。
finally一般用来做一些清理操作。
下面是else和finally使用示例
s1 = 'hello'
try:
int(s1)
except IndexError as e:
print e
except KeyError as e:
print e
except ValueError as e:
print e
#except Exception as e:
# print e
else:
print 'try内代码块没有异常则执行我'
finally:
print '无论异常与否,都会执行该模块,通常是进行清理工作'
六.手动触发异常。
使用raise关键字可以手动触发一个异常类型即使没有任何错误也可以触发。
手动用raise关键字触发的异常也可以让通过try去捕捉哦。
下面是一个手动触发异常的例子在自己写迭代器的时候用到的。
抛出stopiteration异常之后
class c1:
def __init__(self,start,stop):
self.start = start
self.stop = stop
def __iter__(self):
return self
def next(self):
if self.start >= self.stop:
raise StopIteration 手动触发了一个StopIteration异常。
n = self.start
self.start += 1
return n
o1 = c1(1,10)
for i in o1:
print i
自己捕捉自己触发的异常
try:
raise TypeError('类型错误')
except Exception as e:
print e
七.自定义异常类。
自定义异常没什么好说的继承一个异常的基类就可以了下面是个例子。
#_*_coding:utf-8_*_
class TestException(BaseException):
def __init__(self,msg):
self.msg=msg
def __str__(self):
return self.msg
try:
raise TestException('类型错误')
except TestException as e:
print e
八.断言。
在python中做断言需要用到一个assert关键字。
断言从某种意义上来讲像一个精简版的if判断
assert 1 == 1 条件为真时不触发任何异常程序可以继续运行。
assert 1 == 2 条件表达式不为真触发一个AssertionError异常。
九.最后补充。
在什么情况下使用tryexcept来捕捉异常
简单一句话只有在有些异常无法预知的情况下才应该加上tryexcept其他的逻辑错误应该尽量修正。
另外tryexcept一定要少用
本文转自苏浩智 51CTO博客,原文链接:http://blog.51cto.com/suhaozhi/1921000,如需转载请自行联系原作者