重复引起异常 Re-raising Exceptions
有的时候清除工作需要对错误处理和正确处理是不同的,
[Python]异常处理技术(二)
。例如,数据库操作错误需要回滚事务,但是没有错误需要commit操作。这种情况下,你必须要捕获异常并且处理它。中间的层异常 需要被捕获取消之前执行的部分操作,然后继续传播给上层的错误处理。#!/usr/bin/env python
"""Illustrate database transaction management using sqlite3.
"""
import logging
import os
import sqlite3
import sys
DB_NAME = 'mydb.sqlite'
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('db_example')
def throws():
raise RuntimeError('this is the error message')
def create_tables(cursor):
log.info('Creating tables')
cursor.execute("create table module (name text, description text)")
def insert_data(cursor):
for module, description in [('logging', 'error reporting and auditing'),
('os', 'Operating system services'),
('sqlite3', 'SQLite database access'),
('sys', 'Runtime services'),
]:
log.info('Inserting %s (%s)', module, description)
cursor.execute("insert into module values (?, ?)", (module, description))
return
def do_database_work(do_create):
db = sqlite3.connect(DB_NAME)
try:
cursor = db.cursor()
if do_create:
create_tables(cursor)
insert_data(cursor)
throws()
except:
db.rollback()
log.error('Rolling back transaction')
raise
else:
log.info('Committing transaction')
db.commit()
return
def main():
do_create = not os.path.exists(DB_NAME)
try:
do_database_work(do_create)
except Exception, err:
log.exception('Error while doing database work')
return 1
else:
return 0
if __name__ == '__main__':
sys.exit(main())
这个案例中在do_database_work()中使用了一个分离的异常处理,取消之前的数据库操作,然后全局的异常处理器会打印出错误信息。
$ python sqlite_error.py
INFO:db_example:Creating tables
INFO:db_example:Inserting logging (error reporting and auditing)
INFO:db_example:Inserting os (Operating system services)
INFO:db_example:Inserting sqlite3 (SQLite database access)
INFO:db_example:Inserting sys (Runtime services)
ERROR:db_example:Rolling back transaction
ERROR:db_example:Error while doing database work
Traceback (most recent call last):
File "sqlite_error.py", line 51, in main
do_database_work(do_create)
File "sqlite_error.py", line 38, in do_database_work
throws()
File "sqlite_error.py", line 15, in throws
raise RuntimeError('this is the error message')
RuntimeError: this is the error message
保留错误跟踪信息 Preserving Tracebacks
很多时候在你的程序中,异常中清理程序自己又引起了其他的异常,
电脑资料
《[Python]异常处理技术(二)》(https://www.unjs.com)。这种情况一般是发生在系统资源(内存,硬盘资源等..)不足的时候。在异常处理中引起的异常可能会覆盖了原先根本的异常,如果没有对这些异常中的异常没有被处理。#!/usr/bin/env python
import sys
import traceback
def throws():
raise RuntimeError('error from throws')
def nested():
try:
throws()
except:
cleanup()
raise
def cleanup():
raise RuntimeError('error from cleanup')
def main():
try:
nested()
return 0
except Exception, err:
traceback.print_exc()
return 1
if __name__ == '__main__':
sys.exit(main())
当在处理原本错误的时候,cleanup()方法引起一个异常,那么异常处理机制就会重置去处理新的错误。(所以我们只看到异常中的异常了,原本引起的异常就没有了)
$ python masking_exceptions.py
Traceback (most recent call last):
File "masking_exceptions.py", line 21, in main
nested()
File "masking_exceptions.py", line 13, in nested
cleanup()
File "masking_exceptions.py", line 17, in cleanup
raise RuntimeError('error from cleanup')
RuntimeError: error from cleanup
即使第二个异常被捕获了,也没法保证原本的异常被保存。
#!/usr/bin/env python
import sys
import traceback
def throws():
raise RuntimeError('error from throws')
def nested():
try:
throws()
except:
try:
cleanup()
except:
pass # ignore errors in cleanup
raise # we want to re-raise the original error
def cleanup():