异常处理

什么是异常:

异常理解为在程序正常的执行过程中,出现的不属于正常控制流的其他情况。
导致异常发生的情况是由于未在预期范围内的是执行时出现的中断,未在预期范围内的情况有很多,比如对于是调用指定文件或者目录时对于不存在情况的异常,算为可控范围,还有使用request模块时,发请求时遇到的各类连接失败问题,异常导致中断,所以合理对异常的处理,可以在执行前扩大对代码可以正常执行的环境,对这种可能会导致程序中断退出的内容,都需要妥善处理,从而来增强代码的健壮性。

异常的处理:

对于异常的处理,可以从以下两个步骤进行考虑
步骤:

检测是否发生预期异常

为预期发生的异常进行操作,保证程序在可控范围内执行 **
检测到异常,重要的如何解决异常的问题,能够保证程序正常执行,或者为最低影响程序正常执行,也可以自定义异常,将不符合预期要求的程序的结果通过捕获,抛出,或者执行语句

操作有以下:
忽略异常,记录异常信息到日志
执行操作,能够保证程序正常执行,或者为最低影响程序正常执行
记录异常信息,抛出,中断程序(可以不捕获这类异常,当异常发生后直接使程序中断,但是不会记录在日志中)

1. 抛出异常

用已有的异常的类标记抛出
标准输出格式:

 raise MyException("Error message")

自定义异常类(https://blog.csdn.net/skullFang/article/details/78820541)

用于在主动需要抛出的异常,抛出异常中断程序

# 自定义异常
class CmdbRequestPostError(Exception):
    pass
 
def request_data_from_cmdb(cmdb_storage_api, data):
 
    get_params, body, headers = signature_auth(data, cmdb_storage_secret)
 
    url = CMDB_BASIC_API + cmdb_storage_api + "?" + get_params
 
    retry = 0
 
    while True: # 只捕获requests.exceptions.Timeout得异常,当捕获到时,进行request重试,重试5次后仍然为该异常,则抛出异常,退出程序
 
        try:
 
            r = requests.post(url, data=body, headers=headers)
            break
        except requests.exceptions.Timeout as e:
 
            logger.warn(
                repr(e) + ' while send post request to {url}'.format(url=url))
 
            retry += 1
            time.sleep(10)
 
            if retry == 5:
                logger.error(repr(e) +
                ' The maximum number of retries has been exceeded 5, while retries the post request to {url}'.format(url=url))
                raise
 
   _msg = 'api: ' + CMDB_BASIC_API + cmdb_storage_api + ' return: ' + r.text
 
    # r.text's format is like this:
    # '{"code":0,"data":[]}'
    # When the code is not 0, the format like this:
    # '{"code":401}'
 
    result = utfjson.load(r.text)
 
# 由于不符合0的返回码会导致后续的程序的中断,所以自定义异常进行抛出,并记录到日志
    if result["code"] == 0:
        logger.info(_msg)
        return result
 
    else:
        logger.error(_msg)
        raise CmdbRequestPostError(
            _msg + ' The {result} is not 0 '.format(result=result))
2. 捕获异常及处理

1)发生异常不想中断,执行异常发生后才会执行的操作,保证程序进行下去的用法:

try:
    <语句>        #运行别的代码
except <名字> as <数据>:
    <语句>        #如果引发了'name'异常,执行操作
else:
    <语句>        #如果没有异常发生
 
 
# Example:
...
    try:  # try中只放可能会发生异常的语句
        old_applications = os.listdir(prometheus_file_sd_dir)
 
 
    except OSError as e: # 对捕获到的异常如果是OSError,则执行以下语句
        logger.exception(repr(e) + ' while list the dirs in {prometheus_file_sd_dir}'.format(
            prometheus_file_sd_dir=prometheus_file_sd_dir))
 
    else: # 对于未捕获到异常时,程序执行以下语句
        for old_application in old_applications:
 
            if old_application not in applications:
                fsutil.remove(
                    prometheus_file_sd_dir + '{old_application}'.format(old_application=old_application))

2)捕获到异常后执行,重复抛出异常,不常用

try:
    raise NameError
except NameError as e:
    logger.error('Error message') # 可以记录异常信息
    e.args += ('more info',) # 可以对异常的抛出信息增加描述
    raise #raise后不加任何字符

3)不管是否发生异常,必须执行的操作,try…finally

try:
    <语句>
except <name> as <数据>:
    <语句>
finally:
    <语句> #退出try时总会执行,当捕获到异常后直接跳到finally,执行完finally的内容后,再回去再次触发异常,执行异常触发执行的语句

在捕获异常后,必须要有except或者finally进行处理,否则try毫无意义

原则:

  1. 只处理可以预期到的异常,捕获然后执行语句使得不影响程序执行 抛出的异常应该说明原因,常用 logger.error(‘Errormessage’)
  2. try中只执行有可能发生异常的语句,不需要其他没有捕获意义的语句try中只执行有可能发生异常的语句,不需要其他没有捕获意义的语句
  3. 不要使用异常来控制流程,比如故意指定某个异常,然后用except执行正常程序外的内容
  4. 如果有需要,切记使用finally来释放资源
  5. 如果有需要,请不要忘记在处理异常后做清理工作或者回滚操作,比如使用f.close()

好的文章:

异常的用法及规则:https://zhuanlan.zhihu.com/p/33454825
google python 风格指南:https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_language_rules/#id3
对于重复抛出异常的用法:http://www.ianbicking.org/blog/2007/09/re-raising-exceptions.html
xp要求的内容:https://github.com/baishancloud/learn/blob/master/code-style/python.md

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值