• 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)
  • 相关阅读:
    一对一关联
    一对多关联
    软删除
    分层控制器
    系统的助手函数
    tp5命令行基础介绍
    PHP 开启跨域
    生成数据库模型文件
    REST API 安全设计指南
    jquery-Ajax请求用例码
  • 原文地址:https://www.cnblogs.com/angelyan/p/14622270.html
Copyright © 2020-2023  润新知