美文网首页
[Python]装饰器

[Python]装饰器

作者: 胖三斤66 | 来源:发表于2019-03-31 20:34 被阅读0次

    本质:装饰器就是给 python 函数套上一件外套。作用是在不改变原来的函数下,增强函数功能。

    函数装饰器

    def log(func):
        def wrapper(*args, **kw):
            ... # 执行一些操作
            return func(*args, **kw)
        return wrapper
    
    #====================
    @log  # 等价于 now = log(now)  
    def now():
        print('2019/3/31')
    
    print(now(), now.__name__)  
    
    '''
    2019/3/31 wrapper
    '''
    

    通过上述简单的例子,不难发现装饰器就是给 python 函数套上一件外套。作用是在不改变原来的函数下,增强函数功能。

    # 更复杂点的
    # 1. 上例中的 now() 通过装饰器后 __name__ 会发生改变,想要保持不变就需要
    import functools
    def log(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            ...
            return func(*args, **kw)
    
    @log
    def now():
        pass
        
    print(now.__name__)  # 输出是 now 而不再是 wrapper
    
    # 2. 想要在装饰器传参数
    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print(text)
                ...
                return func(*args, **kw)
            return wrapper
        return decorator
    
    @log('hello')  # 等价于 now = log('hello')(now)
    def now():
        pass
    
    # 3. 在 now() 前后分别输出 begin call 和 end call
    def log(func):
        def wrapper(*args, **kw):
            print('begin call')
            res = func(*args, **kw)
            print('end call')
            return res
        return wrapper
    
    # 4. 既能 @log 也能 @log('hello')
    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                return func(*args, **kw)
            return wrapper
        return decorator if isinstance(text, str) else decorator(text)
    
    @log
    def test1():
        pass
    
    @log('hello')
    def test2():
        pass
    

    类装饰器

    相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的 __init____call__ 方法。不管调不调用被装饰的函数,都会先调用类装饰器的 __init__(),调用被装饰的函数后,再调用类装饰器的 __call__()

    class Goo(object):
        def __init__(self, func):
            print('__init__')  
            self._func = func
        
        def __call__(self, *args, **kw):
            print('start call')
            self._func(*args, **kw)
            print('end call')
        
    @Goo
    def test(text):
        print('test', text)
    
    test('world')
    
    '''
    __init__
    start call
    test world
    end call
    '''
    

    相关文章

      网友评论

          本文标题:[Python]装饰器

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