bugstar

导航

Python异常和调试.md

异常捕获

try

基本概念

我们使用try except来捕获异常,python的try except有几个特点:

  • 不管函数内部嵌套几层,只要在try的范围内就可以被捕获。这句话的意思是一个函数被try语句包裹,这个函数中调用了另一个函数。如果被调用函数中发生了异常,那么在外层的函数中是可以被捕获到的;

特点

  • try except finally的执行逻辑是
    ** 正常逻辑是try -》finally
    ** 错误逻辑是try -》except -》finally

except

基本概念

except中有各种类型的异常,其中基类是BaseException。具体可以参考:https://docs.python.org/3/library/exceptions.html#exception-hierarchy

BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning


特点

异常的特点有:

  • 父类的异常捕获到,其后如果有子类也捕获异常,那么子类的异常捕获是失效的
  • 堆栈是按照顺序抛出异常的,在出错的时候可以顺着异常堆栈排查
'a demo class of except'

__author__ = 'liyue'

class  MyExceptionTest:
    #通过try except finally处理异常
    def fun1(self):
        try:
            print('begin to calc 10/0:')
            i = 10/0
            print('calc successful')
        except ZeroDivisionError as e:
            print('ValueError:', e)
        finally:
            print('calc finally')

    #父类捕获异常,子类无效
    def fun2(self):
        try:
            print('begin to calc 10/0:')
            i = 10/0
            print('calc successful')

        except BaseException as be:
            print('This is BaseException :%s' % be) 
        except ZeroDivisionError as e:
            print('This is ValueError:%s' % e)

        finally:
            print('calc finally')

            

if __name__ == '__main__':
    m = MyExceptionTest()
    m.fun1()
    m.fun2()

记录异常

  • 记录异常可以用python內建logging模块,通过配置可以把logging信息记录到日志中。
  • 如果有logging,异常打印后,logging记录完后会继续执行完后续代码
#logging记录异常
    def fun3(self):
        try:
            print('fun3:')
            print('begin to calc 10/0:')
            i = 10/0
            print('calc successful')
        except ZeroDivisionError as e:
            logging.exception(e)
        finally:
            print('3 calc finally')

抛出错误

我们使用raise来抛出错误,特点有:

  • 可以自定义抛出,但是前提是没有內建异常,或者实际需要
  • 可以在except中把适当的exception转换为另一个种抛出,前提是这种转换合理的
'a demo class of except'
__author__ = 'liyue'

import logging

class MyError(ValueError):
    pass

class  MyExceptionTest:
    #通过try except finally处理异常
    def fun1(self, n):
        if n==0:
            raise MyError('This is my error')
        return 10/n

if __name__ == '__main__':
    m = MyExceptionTest()
    m.fun1(0)

调试

print()

print()方法是最常见的调试,在调试中直接打印信息,但是需要每次编码,且最终使用中不方便

assert()

断言也是一种通用的调试方法,但是不友好。使用也不方便

pdb

调试需要配置环境和下载pdb,开发阶段配置好可用,但是不具有通用性。

logging

日志是最有效最通用的方式,既可以调试也可以在非调试环境下使用。
日志的配置有多种形式,api里有说明。这里取了最常用的。多模块可配置打印:

'a demo class of except'
__author__ = 'liyue'

import logging
#logging.basicConfig(filename='d:\example.log',level=logging.DEBUG) #简单的打印
#常见的通用打印,包含了输出路径、输出名称、级别、时间和信息
logging.basicConfig(filename='d:\example.log', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')

class MyDebug(object):

    def assertTest(self, n):
        if n == 0:
            assert()

    def logTest(self, msg):
        #这两句是单模块打印时候使用,如果设计中不需要模块信息输出也可以直接这样使用
        #logging.info(msg)
        #logging.debug(msg)

        #更为通用的多模块打印,是常见的打印模式
        logger = logging.getLogger('ly demo')
        logger.warning(msg)

if __name__ == '__main__':
    m = MyDebug()
    #m.assertTest(0)
    m.logTest('This is a test log info')
    m.logTest('print some infomation')


posted on 2017-12-13 17:58  bugstar  阅读(201)  评论(0)    收藏  举报