python 异常

来源:互联网 发布:淘宝订单支付方式记录 编辑:程序博客网 时间:2024/05/18 00:48

异常不仅仅是错误,还是⼀一种正常的跳转逻辑。


1 异常
除多了个可选的 else 分⽀支外,与其他语⾔言并⽆无多⼤大差别。
>>> def test(n):
... try:
... if n % 2:
... raise Exception("Error Message!")
... except Exception as ex:
... print "Exception:", ex.message
... else:
... print "Else..."
... finally:
... print "Finally..."
>>> test(1)? ? ? ? ? # 引发异常,else 分⽀支未执⾏行,finally 总是在最后执⾏行。
Exception: Error Message!
Finally...
>>> test(2)? ? ? ? ? # 未引发异常,else 分⽀支执⾏行。
Else...
Finally...
关键字 raise 抛出异常,else 分⽀支只在没有异常发⽣生时执⾏行。可⽆无论如何,finally 总会被执⾏行。
可以有多个 except 分⽀支捕获不同类型的异常。
>>> def test(n):
... try:
... if n == 0:
... raise NameError()
... elif n == 1:
... raise KeyError()
... elif n == 2:
... raise IndexError()
... else:
... raise Exception()
... except (IndexError, KeyError) as ex:? # 可以同时捕获不同类型的异常。
... print type(ex)
... except NameError:?? ? ? # 捕获具体异常类型,但对异常对象没兴趣。
... print "NameError"
... except:? ? ? ? ? # 捕获任意类型异常。
116
... print "Exception!"
>>> test(0)
NameError
>>> test(1)
<type 'exceptions.KeyError'>
>>> test(2)
<type 'exceptions.IndexError'>
>>> test(3)
Exception!
下⾯面这种写法已经被 Python 3 抛弃,不建议使⽤用。
>>> def test():
... try:
... raise KeyError, "message"? ? # 相当于 KeyError("Message")
... except (IndexError, KeyError), ex:? # 相当于 as ex
... print type(ex)
⽀支持在 except 中重新抛出异常。
>>> def test():
... try:
... raise Exception("error!")
... except:
... print "catch exception!"
... raise? ? ? ? ? # 原样抛出异常,不会修改 traceback 信息。
>>> test()
catch exception!
Traceback (most recent call last):
raise Exception("error!")
Exception: error!
如果需要,可⽤用 sys.exc_info() 获取调⽤用堆栈上的最后异常信息。
>>> def test():
... try:
... raise KeyError("key error!")
... except:
... exc_type, exc_value, traceback = sys.exc_info()
... sys.excepthook(exc_type, exc_value, traceback)?? # 显⽰示异常信息
>>> test()
Traceback (most recent call last):
117
raise KeyError("key error!")
KeyError: 'key error!'
⾃自定义异常通常继承⾃自 Exception。应该⽤用具体异常类型表⽰示不同的错误⾏行为,⽽而不是 message
这样的状态值。
除了异常,还可以显⽰示警告信息。warnings 模块另有函数⽤用来控制警告的具体⾏行为。
>>> import warnings
>>> def test():
... warnings.warn("hi!")? # 默认仅显式警告信息,不会中断执⾏行。
... print "test..."
>>> test()
UserWarning: hi!

test...


2 断⾔言
断⾔言 (assert) 虽然简单,但远⽐比⽤用 print 输出调试好得多。
>>> def test(n):
... assert n > 0, "n 必须⼤大于 0"? # 错误信息是可选的。
... print n
>>> test(1)
1
>>> test(0)
Traceback (most recent call last):
assert n > 0, "n 必须⼤大于 0"
AssertionError: n 必须⼤大于 0
很简单,当条件不符时,抛出 AssertionError 异常。assert 受只读参数 __debug__ 控制,可以
在启动时添加 "-O" 参数使其失效。

$ python -O main.py


3 上下⽂文
上下⽂文管理协议 (Context Management Protocol) 为代码块提供了包含初始化和清理操作的安全
上下⽂文环境。即便代码块发⽣生异常,清理操作也会被执⾏行。
• __enter__: 初始化环境,返回上下⽂文对象。
118
• __exit__: 执⾏行清理操作。返回 True 时,将阻⽌止异常向外传递。
>>> class MyContext(object):
... def __init__(self, *args):
... self._data = args
...
... def __enter__(self):
... print "__enter__"
... return self._data? ? ? # 不⼀一定要返回上下⽂文对象⾃自⾝身。
...
... def __exit__(self, exc_type, exc_value, traceback):
... if exc_type: print "Exception:", exc_value
... print "__exit__"
... return True? ? ? ? # 阻⽌止异常向外传递。
>>> with MyContext(1, 2, 3) as data:? ? # 将 __enter__ 返回的对象赋值给 data。
... print data
__enter__
(1, 2, 3)
__exit__
>>> with MyContext(1, 2, 3):? ? ? # 发⽣生异常,显⽰示并拦截。
... raise Exception("data error!")
__enter__
Exception: data error!
__exit__
可以在⼀一个 with 语句中使⽤用多个上下⽂文对象,依次按照 FILO 顺序调⽤用。
>>> class MyContext(object):
... def __init__(self, name):
... self._name = name
...
... def __enter__(self):
... print self._name, "__enter__"
... return self
...
... def __exit__(self, exc_type, exc_value, traceback):
... print self._name, "__exit__"
... return True
>>> with MyContext("a"), MyContext("b"):
... print "exec code..."
a __enter__
b __enter__
119
exec code...
b __exit__
a __exit__
contextlib
标准库 contextlib 提供了⼀一个 contextmanager 装饰器,⽤用来简化上下⽂文类型开发。
>>> from contextlib import contextmanager
>>> @contextmanager
... def closing(o):
... print "__enter__"
... yield o
... print "__exit__"
... o.close()? ? ? # 正常情况下要检查很多条件,⽐比如 None,是否有 close ⽅方法等。
>>> with closing(open("README.md", "r")) as f:
... print f.readline()
__enter__
#学习笔记
__exit__
原理很简单,contextmanager 替我们创建 Context 对象,并利⽤用 yield 切换执⾏行过程。
• 通过 __enter__ 调⽤用 clsoing 函数,将 yield 结果作为 __enter__ 返回值。
• yield 让出了 closing 执⾏行权限,转⽽而执⾏行 with 代码块。
• 执⾏行完毕,__exit__ 发送消息,通知 yield 恢复执⾏行 closing 后续代码。
和第 5 章提到的⽤用 yield 改进回调的做法差不多。contextmanager 让我们少写了很多代码。但也
有个⿇麻烦,因为不是⾃自⼰己写 __exit__,所以得额外处理异常。
>>> @contextmanager
... def closing(o):
... try:
... yield o
... except:
... pass? ? ? # 忽略,或抛出。
... finally:? ? ? # 确保 close 被执⾏行。
... o.close()
contextlib 已有现成的 closing 可⽤用,不⽤用费⼼心完善上⾯面的例⼦子。
上下⽂文管理协议的⽤用途很⼲⼴广,⽐比如:
120
• Synchronized: 为代码块提供 lock/unlock 线程同步。
• DBContext: 为代码块中的逻辑提供共享的数据库连接,并负责关闭连接。
• 等等……
???
如果你从没抛出过⾃自定义异常,那么得好好想想了……
0 0
原创粉丝点击