zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    AtCoder Regular Contest 093
    AtCoder Regular Contest 094
    G. Gangsters in Central City
    HGOI 20190711 题解
    HGOI20190710 题解
    HGOI 20190709 题解
    HGOI 20190708 题解
    HGOI20190707 题解
    HGOI20190706 题解
    HGOI 20190705 题解
  • 原文地址:https://www.cnblogs.com/angelyan/p/14622270.html
Copyright © 2011-2022 走看看