zoukankan      html  css  js  c++  java
  • Python装饰器几个有用又好玩的例子

    装饰器是一种巧妙简洁的魔术,类似于Java中的面向切面编程,我们可以再函数执行前、执行后、抛出异常时做一些工作。利用装饰器,我们可以抽象出一些共同的逻辑,简化代码。而简化代码的同时,就是在增加代码鲁棒性。

    一、缓存

    # coding:utf8
    import time
    import json
    
    """
    简单的内存缓存参数
    """
    
    
    def simple_cache(timeout=3):
        def decorator(f):
            def ff(*args, **kwargs):
                arg = json.dumps([args, kwargs])
                res = None
                key = f.__module__ + f.__name__ + arg
                if hasattr(f, key):
                    res = getattr(f, key)
                    if time.time() - res['last_time'] > timeout:
                        res = None
                if res is None:
                    res = {'last_time': time.time(), 'data': f(*args, **kwargs)}
                    setattr(f, key, res)
                return res['data']
    
            return ff
    
        return decorator
    
    if __name__ == '__main__':
        @simple_cache(timeout=3)
        def haha(user_id):
            print("haha", user_id)
    
    
        @simple_cache(timeout=3)
        def baga(user_id):
            print("baga", user_id)
    
    
        haha(0)
        baga(0)
        haha(0)
        haha(1)
        time.sleep(5)
        haha(1)
    

    二、重试

    在进行网络请求时,我们常常需要重试几次才能请求成功。这种套路经常使用,却又嵌套的非常丑陋。此时,我们可以用装饰器将重试逻辑抽象出来。

    def retry(count=1):
        def dec(f):
            def ff(*args, **kwargs):
                ex = None
                for i in range(count):
                    try:
                        ans = f(*args, **kwargs)
                        return ans
                    except Exception as e:
                        ex = e
                raise ex
    
            return ff
    
        return dec
    
    
    db = []
    
    
    @retry(count=10)
    def until_six():
        db.append("haha")
        print("until_six")
        return db[6]
    
    
    print(until_six())
    
    

    三、兼容旧版参数

    库都是随着时间变化而不断丰富的,函数的参数有可能发生变化,使用注解可以简洁完美地兼容旧版本。

    lib.py

    def add(x, y):
        return x + y
    
    

    haha.py

    from lib import add
    
    z = add(x=4, y=5)
    print(z)
    
    

    现在库函数add需要把x变成one,y变成two,同时需要保持haha.py正常运行。
    lib.py

    change_list = {  # 存放函数名称变化表,统一维护
        'add': {
            'x': 'one',
            'y': 'two',
        }
    }
    
    
    def legacy(f):
        def ff(*args, **kwargs):
            if f.__name__ in change_list:
                for old_arg, new_arg in change_list[f.__name__].items():
                    if new_arg not in kwargs and old_arg in kwargs:
                        kwargs.update({new_arg: kwargs.get(old_arg)})
                        del kwargs[old_arg]
            print(kwargs)
            return f(**kwargs)
    
        return ff
    
    
    @legacy
    def add(one, two, **kwargs):
        return one + two
    
    

    这种方式可以把API的全部变化放到一个统一的配置文件里面,当决定不再支持旧版时,直接从配置文件里面把旧版参数删除掉即可。

    四、deprecated

    import logging
    
    
    def deprecated(info):
        def decorator(f):
            def ff(*args, **kwargs):
                logging.warning("%s is deprected. %s" % (f.__name__, info))
                res = f(*args, **kwargs)
                return res
    
            return ff
    
        return decorator
    
    
  • 相关阅读:
    codevs 1766 装果子
    codevs 1415 比那名居天子
    codevs 1388 砍树
    codevs 1373 射命丸文
    codevs 2867 天平系统3
    codevs 2866 天平系统2
    codevs 2865 天平系统1
    codevs 2832 6个朋友
    广搜优化题目总结
    Codeforces Round #578 (Div. 2)
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/8889804.html
Copyright © 2011-2022 走看看