14 python异常处理,调试,单元测试以及文档测试

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_16949707/article/details/53929404

1 python错误处理

1 try的运行机制

利用打印错误这种方式很low

def bar():
    r = foo()
    if r==(-1):
        print('Error')
    else:
        pass

所以高级语言通常都内置了一套try…except…finally…的错误处理机制,Python也不例外。

try:
    print('try...')
    r = 10 / 0
    print('result:', r)#这里try后出现错误,则后续代码不会继续执行
except ZeroDivisionError as e:#如果有这个错误则跳到这里进行处理,而不是处理后续代码
    print('except:', e)
finally:#如果有finally语句块,则except后会执行
    print('finally...')
print('END')
try...
('except:', ZeroDivisionError('integer division or modulo by zero',))
finally...
END

总结如下,try如果遇到错误不往下执行代码,而是跳到except执行,然后再inally,再到最后跳过了错误?

没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)。

你还可以猜测,错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。没错,可以有多个except来捕获不同类型的错误:

2 多类异常

try:
    print('try...')
    r = 10 / int('a')#int也可以抛出一个异常,判断这个数是否为整数
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
finally:
    print('finally...')
print('END')
try...
('ValueError:', ValueError("invalid literal for int() with base 10: 'a'",))
finally...
END
#多类异常注意事项
try:
    print str(1)
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')
1

第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。

常见异常类型及继承关系如下: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
  File "<ipython-input-7-e0cfe9de490f>", line 2
    +-- SystemExit
    ^
IndentationError: unexpected indent

3 错误的传递

# err.py:
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    bar('0')

main()
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-10-1d7596361dc9> in <module>()
      9     bar('0')
     10 
---> 11 main()


<ipython-input-10-1d7596361dc9> in main()
      7 
      8 def main():
----> 9     bar('0')
     10 
     11 main()


<ipython-input-10-1d7596361dc9> in bar(s)
      4 
      5 def bar(s):
----> 6     return foo(s) * 2
      7 
      8 def main():


<ipython-input-10-1d7596361dc9> in foo(s)
      1 # err.py:
      2 def foo(s):
----> 3     return 10 / int(s)
      4 
      5 def bar(s):


ZeroDivisionError: integer division or modulo by zero

4 记录错误

如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

Python内置的logging模块可以非常容易地记录错误信息:

# err_logging.py

import logging

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')#抛出异常后继续执行此句
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
  File "<ipython-input-12-143dc3a3d615>", line 13, in main
    bar('0')
  File "<ipython-input-12-143dc3a3d615>", line 9, in bar
    return foo(s) * 2
  File "<ipython-input-12-143dc3a3d615>", line 6, in foo
    return 10 / int(s)
ZeroDivisionError: integer division or modulo by zero


END

上面同样是错误,但抛出异常然后再继续执行了

5 抛出错误

利用raise可以抛出自己设置的错误

class FooError(ValueError):#新建一个异常类(选择好继承关系就好),可以用于抛出,因为异常也是一个类
    pass

def foo(s):
    n = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)
    return 10 / n

foo('0')
---------------------------------------------------------------------------

FooError                                  Traceback (most recent call last)

<ipython-input-15-8887d546fc87> in <module>()
      8     return 10 / n
      9 
---> 10 foo('0')


<ipython-input-15-8887d546fc87> in foo(s)
      5     n = int(s)
      6     if n==0:
----> 7         raise FooError('invalid value: %s' % s)
      8     return 10 / n
      9 


FooError: invalid value: 0

避免重复抛出异常

def foo(s):
    n = int(s)
    if n==0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise

bar()
ValueError!



---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-16-ae878a7f35c1> in <module>()
     12         raise
     13 
---> 14 bar()


<ipython-input-16-ae878a7f35c1> in bar()
      7 def bar():
      8     try:
----> 9         foo('0')
     10     except ValueError as e:
     11         print('ValueError!')


<ipython-input-16-ae878a7f35c1> in foo(s)
      2     n = int(s)
      3     if n==0:
----> 4         raise ValueError('invalid value: %s' % s)
      5     return 10 / n
      6 


ValueError: invalid value: 0
# err_reraise.py

def foo(s):
#      n = int(s)
#     if n==0:
#         raise ValueError('invalid value: %s' % s)
    return 10 / s

def bar():
    try:
        foo(0)
    except ValueError as e:
        print('ValueError!')
        raise

bar()
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-21-b83fbf519e8b> in <module>()
     14         raise
     15 
---> 16 bar()


<ipython-input-21-b83fbf519e8b> in bar()
      9 def bar():
     10     try:
---> 11         foo(0)
     12     except ValueError as e:
     13         print('ValueError!')


<ipython-input-21-b83fbf519e8b> in foo(s)
      5 #     if n==0:
      6 #         raise ValueError('invalid value: %s' % s)
----> 7     return 10 / s
      8 
      9 def bar():


ZeroDivisionError: integer division or modulo by zero

2 调试

1 断言assert

def foo(n):
    print type(n)
    assert n != 0,'n is zero!'
    return 10 / n
def main():
    foo(0)
main()
<type 'int'>



---------------------------------------------------------------------------

AssertionError                            Traceback (most recent call last)

<ipython-input-26-4740780af009> in <module>()
      5 def main():
      6     foo(0)
----> 7 main()


<ipython-input-26-4740780af009> in main()
      4     return 10 / n
      5 def main():
----> 6     foo(0)
      7 main()


<ipython-input-26-4740780af009> in foo(n)
      1 def foo(n):
      2     print type(n)
----> 3     assert n != 0,'n is zero!'
      4     return 10 / n
      5 def main():


AssertionError: n is zero!

2 logging

import logging

s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-27-34acd0c1650a> in <module>()
      4 n = int(s)
      5 logging.info('n = %d' % n)
----> 6 print(10 / n)


ZeroDivisionError: integer division or modulo by zero
import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

<ipython-input-28-7501ca4b96cb> in <module>()
      4 n = int(s)
      5 logging.info('n = %d' % n)
----> 6 print(10 / n)


ZeroDivisionError: integer division or modulo by zero

没发现有啥用

3 pdb

python -m pdb err.py运行程序,可以用于调试代码

l #查看代码
n #下一步
p #打印
q #退出
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-29-27f5dfd249af> in <module>()
----> 1 l #查看代码
      2 n #下一步
      3 p #打印
      4 q #退出


NameError: name 'l' is not defined

pdb.set_trace()可以在想要的地方设置断点

3单元测试

就是利用python自带的unittest模块,编写一个测试类,里面有很多种测试方法,批量的对代码进行测试,这样很方便,待代码修改后还可以继续调用,很好~~

class Dict(dict):

    def __init__(self, **kw):
        super().__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value
import unittest
#from mydict import Dict
class TestDict(unittest.TestCase):

    def test_init(self):
        d = Dict(a=1, b='test')
        self.assertEqual(d.a, 1)
        self.assertEqual(d.b, 'test')
        self.assertTrue(isinstance(d, dict))

    def test_key(self):
        d = Dict()
        d['key'] = 'value'
        self.assertEqual(d.key, 'value')

    def test_attr(self):
        d = Dict()
        d.key = 'value'
        self.assertTrue('key' in d)
        self.assertEqual(d['key'], 'value')

    def test_keyerror(self):
        d = Dict()
        with self.assertRaises(KeyError):
            value = d['empty']

    def test_attrerror(self):
        d = Dict()
        with self.assertRaises(AttributeError):
            value = d.empty
#以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
if __name__ == '__main__':
    unittest.main()

直接在jupyter notebook里面运行会报错,正确的做法是编辑俩个.py文件,然后在运行…test.py那个即可
具体参考:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191629979802b566644aa84656b50cd484ec4a7838000

huxiang@shenyong-Opt790:~/work/test vimydict.pyhuxiang@shenyongOpt790: /work/test vi mydict_test.py
huxiang@shenyong-Opt790:~/work/test$ python mydict_test.py

EEEEE

ERROR: test_attr (main.TestDict)

Traceback (most recent call last):
File “mydict_test.py”, line 17, in test_attr
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)

======================================================================

ERROR: test_attrerror (main.TestDict)

Traceback (most recent call last):
File “mydict_test.py”, line 28, in test_attrerror
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)

======================================================================

ERROR: test_init (main.TestDict)

Traceback (most recent call last):
File “mydict_test.py”, line 6, in test_init
d = Dict(a=1, b=’test’)
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)

======================================================================

ERROR: test_key (main.TestDict)

Traceback (most recent call last):
File “mydict_test.py”, line 12, in test_key
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)

======================================================================

ERROR: test_keyerror (main.TestDict)

Traceback (most recent call last):
File “mydict_test.py”, line 23, in test_keyerror
d = Dict()
File “/home/huxiang/work/test/mydict.py”, line 4, in init
super().init(**kw)
TypeError: super() takes at least 1 argument (0 given)


Ran 5 tests in 0.001s

FAILED (errors=5)

4 文档测试

# mydict2.py
class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

if __name__=='__main__':
    import doctest
    doctest.testmod()

运行什么结果也没有,代表代码是正确的,如果把getattr注释掉,则会报错:

# mydict2.py
class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

#     def __setattr__(self, key, value):
#         self[key] = value

if __name__=='__main__':
    import doctest
    doctest.testmod()
**********************************************************************
File "__main__", line ?, in __main__.Dict
Failed example:
    d1['y']
Exception raised:
    Traceback (most recent call last):
      File "/home/huxiang/anaconda2/envs/tensorflow/lib/python2.7/doctest.py", line 1315, in __run
        compileflags, 1) in test.globs
      File "<doctest __main__.Dict[4]>", line 1, in <module>
        d1['y']
    KeyError: 'y'
**********************************************************************
1 items had failures:
   1 of   9 in __main__.Dict
***Test Failed*** 1 failures.

猜你喜欢

转载自blog.csdn.net/qq_16949707/article/details/53929404