48-调试器(1)

复习异常:

try:          #有可能发生异常部分
    print('try...')
    #r = 10 / 2
    r = 10 / 0
    print('result:', r) #如果正常会走到这里
except ZeroDivisionError as e: #发生除零异常会走到这里 {没有就跳过except}
    print('except:', e)
finally:                #必定会走finally {当然,这个finally部分可以不写}
    print('finally...')
print('END\n')


try:
    print('try...')
    #r = 10 / int('0')    #分母为0,ZeroDivisionError
    r = 10 / int('hao') #'hao'无法转化成数字,ValueError
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
finally:
    print('finally...')
print('END\n')


try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else: #当所有except都没有执行就执行else,当然这个else也是可省略的
    print('no error!')
finally:
    print('finally...')
print('END\n')


#所有的错误类型都继承自BaseException,except会把当前xxxError以及这个xxxError的子类都捕获到,
#故而设计except的时候要注意这一点,不要设计冗余无用的except分支
try:
    r = 10 / int('abc')
except ValueError as e:
    print('ValueError')
except UnicodeError as e: #UnicodeError是ValueError的子类,所以ValueError会把
    print('UnicodeError') #UnicodeError冲掉,UnicodeError这个分支永远不会执行,故可以删去
#详细继承关系,
#见官网:https://docs.python.org/3/library/exceptions.html#exception-hierarchy


#由于异常可以穿越多层调用,层层传递,故只需要在合适的层次catch和except即可。
#比如,foo()出错了,错误被传递至bar,main,只需要在main(),catch和except就可以了。
'''
def foo(s):
    return 10 / int(s)

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

def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally...')
'''
#错误层层上抛,形成调用栈:
# def foo(s):
    # return 10 / int(s) #两类错:1.除0;2.非数字串

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

# def main():
    # bar('0')
# main()
#main()处首先报错,是由于bar()引发的,而bar()的错又是foo()引发的,根源是foo(),但
#但是可以在main()处except


#logging:既能记录错误栈,也能保证程序继续运行下去
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\n') #若程序能到这里,说明前面的logging的确能支持 “程序遇到错误后,依旧正常运行”


#错误的本质是class,所以捕获错误catch到的就是这个class的一个instance
#故而我们可以继承已有的xxxError,自定义一个错误的class,并用raise在合适的时机抛出错误
class FooError(ValueError): #自定义的错误class
    pass

# def foo(s):
    # n = int(s)
    # if n==0:
        # raise FooError('invalid value: %s' % s) #防止程序往下走,因为再往下就要除0了
    # return 10 / n

# foo('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    #把ValueError原封不动地向bar()的上层抛,让调用bar()的上层处理错误
        # # raise ValueError('input error') #把错误稍作处理再往上层抛
# bar()



#########################################################################################
#作业:定位错误
from functools import reduce
from decimal import *
def str2num(s):    #可能s不是‘整数数字串’,引发ValueError
    #return int(s)  #int()要求传入 {整数数字串}
    return Decimal(s) #把数字串转化成10进制的数字
def calc(exp):
    ss = exp.split('+') #根据+ 把exp分割成一个list
    ns = map(str2num, ss) #把这个list的每个元素由str变成int
    return reduce(lambda acc, x: acc + x, ns) #等价于sum(ns)

def main():
    r = calc('100 + 200 + 345')
    print('100 + 200 + 345 =', r)
    r = calc('99 + 88 + 7.6')
    print('99 + 88 + 7.6 =', r)

main()
posted @ 2018-03-04 14:20  hzhang_NJU  阅读(106)  评论(0)    收藏  举报