美文网首页
17 装饰器的使用[python基础]

17 装饰器的使用[python基础]

作者: 乱弹琴给 | 来源:发表于2020-01-11 11:38 被阅读0次

装饰器

1. 

用于拓展原来函数功能的一种函数
2.
返回函数的函数
3.
在不用更改原函数的代码前提下给函数增加新的功能

//如果没有装饰器
def hello():
    print('hello world')

def test():
    print('test...')

def hello_wrapper():
    //新的函数,包裹原来的hello
    print('进入函数hello')
    hello()
    print('结束执行hello')

def test_wrapper():
    print('进入函数hello')
    test()
    print('结束执行hello')

if __name__ == '__main__':
    //要实现这样的功能,就要建立多个wrapper(),而且有变化需要修改多个地方,不好维护
    hello_wrapper()
    test_wrapper()

//实现装饰器,用装饰器实现
def log(func)
    //记录函数执行的日志
    def wrapper():
        print('start...')
        func()
        print('end...')

def log_in(func)
    //记录函数执行的日志
    def wrapper():
        print('开始...')
        func()
        print('结束...')

@log
def hello():
    //简单功能模拟
    print('hello world')

@log
@log_in   //装饰器可以使用多个,按顺序嵌套执行
def test()
    print('test...')

if __name__ == '__main__':
    hello()
    test()

//带参数的装饰器
def log(name = None):  //允许默认值,可以不传参
    
    def decorator(fun):
        def wrapper():
            print('{0} start...'.format(name))
            fun()
            print('{0} end...'.format(name))
        return wrapper
    return decorator                     //返回函数不要带括号

@log('hello')  //也可以不传参 @log()
def hello():
    print('hello world')

@log('test')
def test():
    print('test...')

if __name__ == '__main__':
    hello()
    test()

//如果带参数的装饰器,同时自定义的函数本身也带参数和返回值,如何传递使用

def log(name = None):  //允许默认值,可以不传参
    
    def decorator(func):  
        def wrapper(*args, **kwargs):       //这里就要传入add(a, b)的参数.用两个魔法参数,一个元组,一个字典
            print('{0} start...'.format(name))
            rest = func(*args, **kwargs)                //这里就要传入add(a, b)的参数,用一个临时变量保存返回值
            print('{0} end...'.format(name))
            return rest   //为了执行上一句打印,在这里返回临时变量值
        return wrapper
    return decorator                     //返回函数不要带括号

@log('hello')  //也可以不传参 @log()
def hello():
    print('hello world')

@log('test')
def test():
    print('test...')

def  add(a, b, *args, **kwargs):    //有参数,有返回值,如何使用,带两个魔法参数,传更多的变量
    return a + b

if __name__ == '__main__':
    //hello()
    //test()

    rest = add(5, 6, k = 5, v = 6)

///装饰器之wraps

def log(name = None):  //允许默认值,可以不传参
    
    def decorator(func):  
        @wraps(func)    //j加上这个装饰器,就可以解决注释__doc__和名字__name__等被改变的问题
        def wrapper(*args, **kwargs):       //这里就要传入add(a, b)的参数.用两个魔法参数,一个元组,一个字典
            //注释:装饰器内部的函数
            print('{0} start...'.format(name))
            rest = func(*args, **kwargs)                //这里就要传入add(a, b)的参数,用一个临时变量保存返回值
            print('{0} end...'.format(name))
            return rest   //为了执行上一句打印,在这里返回临时变量值
             //原始hello()的注释名字是在这附近发生了改变  ,如果不用@wraps需要在下面进行手动更改
        //wrapper.__doc__ = func.__doc__
        //wrapper.__name__ = func.__name__
        //但是每个都这么操纵很麻烦,所以pyton提供了一个@wraps用来使用,放在装饰器内部函数上

                
        return wrapper
    return decorator                     //返回函数不要带括号

@log('hello')  //也可以不传参 @log()
def hello():
    //注释:简单功能模拟
    print('hello world')

  if __name__ == '__main__':
    print('doc: {0}'.format(hello.__doc__))
    print('doc: {0}'.format(hello.__name__))  //结果注释和名字都不是hello()的,而是变成了装饰器内部的函数wrapper()的注释和名字,这时候就需要用到@wraps
    hello()

///装饰器注意事项:
1,用@wraps 还原原始函数的注释\名字等信息
2,用魔法传参 *args, **kwargs 解决自己的函数传参问题
3,自己的函数有返回值的,把函数返回值用临时变量保存起来,执行完装饰器内逻辑后,再return
4,也可以用于类

///类的装饰器

def f(self): //可以在这里扩展类的方法
print('{0}: 我爱吃东西'.format(self.name))
print('000000') //

def eat(cls):
//cls.eat = lambda self: print('{0}: 我爱吃东西'.format(self.name)) //简单的用lambda,更丰富可以用下面方法
cls.eat = f
return cls

@eat
class Cat(object):
//猫类
def init(self, name)
self.name = name

if name == 'main':
cat = Cat('小黑')
cat.eat()

相关文章

网友评论

      本文标题:17 装饰器的使用[python基础]

      本文链接:https://www.haomeiwen.com/subject/oavvactx.html