python装饰器实现函数重试

一、介绍

在执行爬虫requests库时,经常会碰到各种的请求失败,有时是超时,有时是代理失败。那么此时我们还是需要拿到数据就必须重试执行几次函数

在代码中就是多来几次函数加括号,或者是来个递归函数,直到执行成功。但还是比较麻烦的。

那么使用装饰器来实现是最好的,需要重试的就加上装饰器,不需要的就不加,这样写代码也更灵活

二、代码

from functools import wraps, partial
import os
import logging
import logging.config as log_conf
import time

log_dir = os.path.dirname(__file__) + '/logs'
if not os.path.exists(log_dir):
    os.mkdir(log_dir)

log_path = os.path.join(log_dir, 'retry.log')

log_config = {
    'version': 1.0,
    'formatters': {
        'detail': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            'datefmt': "%Y-%m-%d %H:%M:%S"
        },
        'simple': {
            'format': '%(name)s - %(levelname)s - %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'formatter': 'detail'
        },
        'file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'maxBytes': 1024 * 1024 * 5,
            'backupCount': 10,
            'filename': log_path,
            'level': 'INFO',
            'formatter': 'detail',
            'encoding': 'utf-8',
        },
    },
    'loggers': {
        'crawler': {
            'handlers': ['console', 'file'],
            'level': 'DEBUG',
        },
        'parser': {
            'handlers': ['file'],
            'level': 'INFO',
        },
        'other': {
            'handlers': ['console', 'file'],
            'level': 'INFO',
        },
        'storage': {
            'handlers': ['file'],
            'level': 'INFO',
        }
    }
}

log_conf.dictConfig(log_config)

r_logger = logging.getLogger('retry')


def retry(times=-1, delay=0, exceptions=Exception, logger=r_logger):
    """
    :param times: 重试次数
    :param delay: 重试间隔时间
    :param exceptions: 想要捕获的错误类型
    :param logger: 指定日志对象输出
    :return: func result or None
    """
    def _inter_retry(caller, retry_time, retry_delay, es):
        while retry_time:
            try:
                return caller()
            except es as e:
                retry_time -= 1
                if not retry_time:
                    logger.error("max tries for {} times, {} is raised, details: func name is {}, func args are {}".
                                 format(times, e, caller.func.__name__, (caller.args, caller.keywords)))
                    raise
                time.sleep(retry_delay)

    def retry_decorator(func):
        @wraps(func)
        def _wraps(*args, **kwargs):
            return _inter_retry(partial(func, *args, **kwargs), times, delay, exceptions)
        return _wraps
    return retry_decorator

三、结果

@retry() #默认无限重试
def get_data():
    print(1)
    res = a + b # 假设函数执行错误
    return res

res = get_data()
print(res)


@retry(5,2) #重试5次,每隔2秒,如果都不成功,就抛出异常
def get_data():
    print(1)
    res = a + b # 假设函数执行错误
    return res

res = get_data()
print(res)
原文地址:https://www.cnblogs.com/angelyan/p/14622270.html