python裝飾器,懂了這篇夠用

1.裝飾器本質是一個函數,該函數的參數是另一個函數。目的增加函數的功能。

2.@語法只是將函數傳入裝飾器函數,並無神奇之處。

一、帶參數的裝飾器(函數)

特點兩層函數

import functools


def log(func):                         #第一層
    @functools.wraps(func)             #爲了解決被裝飾函數的名稱變化的問題
    def wrapper(*args, **kwargs):      #第一層
        print('call %s():' % func.__name__)
        print('args = {}'.format(*args))
        return func(*args, **kwargs)

    return wrapper

使用裝飾器有兩種方式,第一種也就加一個@符號就用了。第二種就是兩次調用。

@log
def test(p):
    print(test.__name__ + " param: " + p)
def test(p):
    print(test.__name__ + " param: " + p)

wrapper = log(test)
wrapper("I'm a param")

 

二、帶參數的裝飾器 (函數)

特點 是三層函數,爲啥三層,因爲要傳除了被裝飾的func函數外,還要傳其他參數。

import functools

def log_with_param(text):                # 第一層
    def decorator(func):                 # 第二層
        @functools.wraps(func)
        def wrapper(*args, **kwargs):    # 第三層
            print('call %s():' % func.__name__)
            print('args = {}'.format(*args))
            print('log_param = {}'.format(text))
            return func(*args, **kwargs)

        return wrapper

    return decorator
    
@log_with_param("param")
def test_with_param(p):
    print(test_with_param.__name__)

理解:

decorator = log_with_param("param")

wrapper = decorator(test_with_param)

wrapper('實際的參數')

使用

test_with_param('實際的參數')  #加了裝飾器的函數,調用還是一樣調用,但是該函數增加了裝飾器 的功能

附上完整的兩個例子

import functools


def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('call %s():' % func.__name__)
        print('args = {}'.format(*args))
        return func(*args, **kwargs)

    return wrapper
@log
def test(p):
    print(test.__name__ + " param: " + p)
    
test("實際參數")


# 運行信息如下:
"""
call test():
args = 實際參數
test param: 實際參數
"""

 

import functools
def log(text):
    print(text)
    def decorator(func):
         @functools.wraps(func)
         def wrapper(*args,**kwargs):
                 res = func(*args,**kwargs)
                 return res
         return wrapper
    
    return decorator



@log('裝飾器參數')
def test(text):
    print(text)

#調用
test('我是被裝飾器的函數的參數')

三、多層裝飾器 

def first_decorator(func):
    print('--first--')

    def first_wrapper(*args, **kwargs):
        print('------first---%s---' % func.__name__)
        return func(*args, **kwargs)
    return first_wrapper


def second_decorator(func):
    print('--second--')

    def second_wrapper(*args, **kwargs):
        print('------second---%s---' % func.__name__)
        return func(*args, **kwargs)
    return second_wrapper

@first_decorator
@second_decorator
def test_func_1():
    print('excute %s' % inspect.stack()[0][3])
def timeit(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        cost = time.time() - start
        print("cost %f second " % cost)
        return ret
    return wrapper


def delay(sec):
    def wrapper(func):
        def _wrapper(*args, **kwargs):
            time.sleep(sec)
            ret = func(*args, **kwargs)
            print("delay %d seconds to call %s" % (sec, func.__name__))
            return ret
        return _wrapper
    return wrapper


@timeit
@delay(2)
def add(a, b):
    return a + b


if __name__ == "__main__":
    add(1, 2)

"""
delay 1 seconds to call add
cost 2 second
"""

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章