python——裝飾器詳解

一、裝飾器概念

1、裝飾器

  • 裝飾器:一種返回值也是一個函數(shù)的函數(shù),即裝飾器。

2、裝飾器目的

  • 裝飾器的目的:裝飾器是用于拓展原函數(shù)的一種函數(shù),可以在不改變原來函數(shù)名或類名的情況下,給原函數(shù)增加新的功能。
    一般情況下,我們需要改變原函數(shù),直接改原函數(shù)的代碼即可,但是實際情況中,并不是所有的函數(shù)代碼(如核心代碼)是不允許隨意更改的,此時使用裝飾器就更為方便。

二、如何創(chuàng)建裝飾器

  • 舉個栗子,如有一簡單函數(shù)
def function1():
    print('i am a funcation!')
  • 現(xiàn)需要將該函數(shù)運行時記錄日志,在該函數(shù)里加上打印日志的代碼即可
def function1():
    print('i am a function!')
    print('function1 is running!')
  • 如果有大批函數(shù)都需要加上打印日志的功能,則無法一個一個去改代碼,最好能使用一個方法,給所有函數(shù)調(diào)用。
def log(func):
    print('%s is runnning!' % func.__name__)
    return func
@log
def function1():
    print('i am a function!')
function1()
>>>
function1 is runnning!
i am a function!
  • 但是裝飾器要求返回的是一個函數(shù)對象,所以我們可以將上述代碼改造一下,使用嵌套函數(shù),使其返回一個函數(shù)對象。
def log(func):
    def _decoration():
        print('%s is runnning!' % func.__name__)
        func()
    return _decoration
@log
def function1():
    print('i am a function!')
function1()
>>>
function1 is runnning!
i am a function!

三、python內(nèi)置裝飾器

@property

  • @property:上篇文章python類的三大特性——封裝有寫到,property,屬性的意思,被修飾的方法,可以使用引用類中字段屬性的方法去調(diào)用。

@staticmethod

  • @staticmethod:靜態(tài)方法,即將類中的方法修飾為靜態(tài)方法,在不創(chuàng)建實例的情況下,可以通過類名直接引用。其成員方法區(qū)別是沒有self參數(shù)。

@classmethod

  • @classmethod:類方法,類方法的第一個參數(shù)是一個類,將類本身作為操作的方法。

四、裝飾器類型

1、無參數(shù)的裝飾器

見上例裝飾器

2、帶固定參數(shù)的裝飾器

def log(func):
    def _decoration(a, b):
        print('%s is runnning!' % func.__name__)
        func(a, b)
    return _decoration
@log
def function1(a, b):
    s = a + b
    print('the result is %d' % s)
    print('i am a function!')
function1(1, 2)
>>>
function1 is runnning!
the result is 3
i am a function!

3、無固定參數(shù)的裝飾器

def log(func):
    def _decoration(*args, **kwargs):
        print('%s is runnning!' % func.__name__)
        func(*args, **kwargs)
    return _decoration
@log
def function1(a, b):
    s = a + b
    print('the result is %d' % s)
    print('i am a function!')

@log
def function2(a, b, c):
    s = a + b - c
    print('the result is %d' % s)
    print('i am a function!')
function1(1, 2)
function2(1, 2, 3)
>>>
function1 is runnning!
the result is 3
i am a function!
function2 is runnning!
the result is 0
i am a function!

4、使用@functools.wraps

栗子如下:

def log(func):
    def _decoration():
        print('%s is runnning!' % func.__name__)
        func()
    return _decoration
@log
def function1():
    print('i am a function!')
    print(function1.__name__)
function1()
>>>
function1 is runnning!
i am a function!
_decoration

發(fā)現(xiàn)此處打印的不是function1的函數(shù)名.
使用上述代碼的缺點就是原函數(shù)的信息不見了. 如: name, 參數(shù)列表等.
所以這里引入@functools.wraps

import functools
def log(func):
    @functools.wraps(func)
    def _decoration():
        print('%s is runnning!' % func.__name__)
        func()
    return _decoration
@log
def function1():
    print('i am a function!')
    print(function1.__name__)
function1()
>>>
function1 is runnning!
i am a function!
function1

5、類裝飾器

import functools
class Log(object):
    def __call__(self, func):
        @functools.wraps(func)
        def _decoration():
            print('%s is runnning!' % func.__name__)
            func()
        return _decoration
@Log()
def function1():
    print('i am a function!')
    print(function1.__name__)
function1()
>>>
function1 is runnning!
i am a function!
function1

6、多個裝飾器的調(diào)用順序

多個類裝飾一個函數(shù)時,調(diào)用時有一定的順序 . 簡單來說,就是裝飾器調(diào)用順序與@ 聲明的順序相反.

五、裝飾器的用途

裝飾器可以在不改變原函數(shù)功能的情況下,給原函數(shù)實現(xiàn)其他功能,同時,又能復用大量代碼,減少冗余.
它常被用于有切面需求的場景, 如: 打印日志, 記錄時間, 權(quán)限校驗, 事務處理, 緩存等場景.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容