python-三器 装饰器(闭包)

我们知道对于一个普通的类,我们要使用其中的函数的话,需要对类进行实例化,而一个类中,某个函数前面加上了staticmethod或者classmethod的话,那么这个函数就可以不通过实例化直接调用

"""
@staticmethod不需要表示自身对象的self和自身类的cls参数。如果在@staticmethod中要调用到这个类的一些属性方法,直接类名.属性名或类名.方法名。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
@property使方法像属性一样调用,就像是一种特殊的属性。有参函数时使用@name.setter
@pysnooper日志打印工具,用显示函数间的入参和返回值的变化
    output='a.txt'    #将结果保存到文件a.txt     
    variables=('a') #打印非局部变量a的值    
    depth=1 #Show snoop lines for functions that your function calls    
    prefix='hello' #在每一行打印信息前添加hello
""" class Animal(object): name = 'dog' def __init__(self,name): self.name = name def intro1(self): print('there is a %s'%(self.name)) @staticmethod def intro2(): print('there is a %s') @staticmethod def intro3(test): print('there is a %s'%(test)) @classmethod def intro4(cls): #不传参 cls.intro1(cls) #调用类方法 print('there is a %s'%(cls.name)) @classmethod def intro5(cls,test): #传参 cls.intro1(cls) #调用类方法 print('there is a %s %s'%(cls.name,test)) @property def intro6(self): print('there is a %s eating'%(self.name)) @intro6.setter def intro7(self,value): print('there is %d %s eating'%(value,self.name)) import pysnooper @pysnooper.snoop() #@pysnooper.snoop('log.log') def lisy(a): return [x - 10 if x in [11, 12, 13] else x for x in a] if __name__ == '__main__': a = Animal('cat') a.intro1() Animal.intro2() Animal.intro3('test') Animal.intro4() Animal.intro5('test') a.intro6 a.intro7=2 lisy([1, 2, 3, 11, 12, 13, '111', 222])

 

装饰器分类

"""
1.修饰无参函数
2.修饰有参函数
3.不带参数的装饰器
4.带参数的装饰器
5.类装饰器
"""


#修饰无参函数
#(无参数时不需要直接调用,在@log1时已经调用了)
def log1(func):
    func()
@log1
def test():
    print('testlog1:',test.__name__)


#修饰有参函数、无参数
def log2(func):
    def inner(*args, **kwargs):
        func(*args, **kwargs)
    return inner
@log2
def test(num):
    print('testlog2:',num,test.__name__)
test(20)


#修饰有参函数(返回入参出参)
def log3(func):
    def inner(*args, **kwargs):
        print('入参:',func.__name__, args, kwargs)
        res =func(*args, **kwargs)
        print('出参:',func.__name__, res)
        return res
    return inner
@log3
def test(num):
    print('testlog3:', num, test.__name__)
    return num
test(30)



from functools import wraps
#@wraps可以保证装饰器修饰的函数的name的值保持不变

#不带参数的装饰器
def log4(func):
    @wraps(func)
    def inner(*args, **kwargs,):
        func(*args, **kwargs)
    return inner
@log4
def test(num):
    print('testlog4:',num,test.__name__)
test(40)


#带参数的装饰器
def log5(level):
    def log(func):
        @wraps(func)
        def inner(*args, **kwargs,):
            if level == "warn":
                print("%s is running" % func.__name__)
            func(*args, **kwargs)
        return inner
    return log
@log5(level="warn")
def test(num):
    print('testlog5:', num, test.__name__)
test(50)


#实现带参数和不带参数的装饰器自适应
def log6(arg):
    if callable(arg):  # 判断入参的参数是否有值,不带参数的装饰器调用这个分支
        def log4(func):
            @wraps(func)
            def inner(*args, **kwargs, ):
                func(*args, **kwargs)
            return inner
        return log4
    else:
        def log5(func):
            @wraps(func)
            def inner(*args, **kwargs,):
                if arg == "warn":
                    print("%s is running" % func.__name__)
                func(*args, **kwargs)
            return inner
        return log5
@log6(arg=None)
def test(num):
    print('testlog:', num, test.__name__)
test(0)



#类装饰器
class Loging:
    def __init__(self, level):
        self.level = level
    def __call__(self, func):
        @wraps(func)
        def inner(*args, **kwargs):
            if self.level == "warn":
                print("%s is running" % func.__name__)
            func(*args, **kwargs)
        return inner

@Loging(level="warn")
def test(num):
    print('testLoging:', num, test.__name__)
test(0)


class LogClass:
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print('初始化装饰器')
        self.func(*args, **kwargs)
        print('中止装饰器')
@LogClass
def test(num):
    print('testLogClass:', num)
test(0)

 

装饰器应用

def log(func):
    def inner(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except Exception as e:
            print(e)
            print('截图')
        finally:
            print('清除test函数')
    return inner

@log
def test():
    raise Exception("抛出一个异常")
test()

 

def fixedFuncOnce(func):
    """
    修饰函数(固定函数只执行一次)-有返回
    @param func:
    @return:
    """
    cache = {}
    @wraps(func)
    def inner(*args,**kwargs):
        key = func.__name__ #函数的名称作为key
        result = None
        if key in cache.keys():
            result = cache[key]
        #key不存在
        if result is None:
            result = func(*args, **kwargs)
            cache[key] = result
        return result
    return inner


def fixedTimeOnce(func):
    """
    修饰函数(固定时间只执行一次)-有返回
    @param func:
    @return:
    """
    cache = {}
    @wraps(func)
    def inner(*args,**kwargs):
        key = func.__name__ #函数的名称作为key
        result = None
        if key in cache.keys():
            (tmp,updateTime) = cache[key]
            if time.time() -updateTime < 5:
                result=tmp
        #key不存在、或者过期
        if result is None:
            result = func(*args, **kwargs)
            cache[key] = (result, time.time())
        return result
    return inner



def sameParameterOnce(func):
    """
    修饰函数(相同参数值只执行一次)-有参数
    @param func: 目标函数
    @return:
    """
    savefunc = {}
    @wraps(func)
    def inner(*args, **kwargs):
        key = func.__name__
        result = None
        if key in savefunc.keys():
            ss = savefunc[key]
            f = lambda x: x.get("args") == args and x.get("kwargs") == kwargs
            if list(filter(f,ss)):  #判断函数参数
                result = ss[0]["result"]
            else:                   #或者参数不一样
                result = func(*args, **kwargs)
                savefunc[key].append({"args": args, "kwargs": kwargs, "result": result})
        else:                       #key不存
            result = func(*args, **kwargs)
            savefunc[key] = [{"args": args,"kwargs": kwargs,"result": result}]
        return result
    return inner

 

posted @ 2021-04-13 17:59  南方的墙  阅读(77)  评论(0编辑  收藏  举报