Python-02進階-02裝飾器

Python-00裝飾器

裝飾器

[toc]

TODO

總結(jié)

裝飾器的作用就是為已經(jīng)存在的函數(shù)或?qū)ο筇砑宇~外的功能

裝飾器使用種類:

  • 函數(shù)裝飾器
  • 類裝飾器
  • 函數(shù)裝飾器裝飾 類
  • 類裝飾器裝飾 函數(shù)

裝飾器樣例

@staticmethod
@logging
def a():
    return 1
    pass
等價于
a = staticmethod(logging(a)) 

默認(rèn)裝飾器函數(shù)

  • @property
    通過property裝飾器控制類的屬性的綁定與獲取,一般就是給某個屬性增加一個驗證類型等功能。
  • @staticmethod
    將被裝飾的函數(shù)從類中分離出來,該函數(shù)不能訪問類的屬性,簡單說可以將該函數(shù)理解為一個獨立的函數(shù),不允許使用self。
    staticmethod 就是將該被裝飾的函數(shù)與該類沒有關(guān)系,該函數(shù)不能用self傳參,需要和普通函數(shù)一樣傳參。
  • @classmethod
    classmethod 可以用來為一個類創(chuàng)建一些預(yù)處理的實例.類方法只能找類變量,不能訪問實例變量

裝飾器庫 functools
因為使用裝飾器 functools 會導(dǎo)致函數(shù)或類信息缺失。
例如 func.__name__
所以需要使用 functools 裝飾器庫處理

使用方法:
每個裝飾器前面加上下句話即可
@functools.wraps(func)
樣例如下所示:

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print '%s %s():' % (text, func.__name__)
            return func(*args, **kw)
        return wrapper
    return decorator

裝飾器&函數(shù)

函數(shù)簡單說明

參考鏈接: 12步輕松搞定python裝飾器

了解裝飾器之前也需要了解內(nèi)部函數(shù)與函數(shù)閉包。

參考鏈接: 內(nèi)部函數(shù)&函數(shù)閉包

內(nèi)部函數(shù)

def wai_hanshu(canshu_1):

  def nei_hanshu(canshu_2): # 我在函數(shù)內(nèi)部有定義了一個函數(shù)
    return canshu_1*canshu_2

  return nei_hanshu  # 我將內(nèi)部函數(shù)返回出去

a = wai_hanshu(123)   # 此時 canshu_1 = 123
print a
print a(321)  # canshu_2 = 321

閉包說明
參考鏈接: 函數(shù)閉包
python中的閉包從表現(xiàn)形式上定義(解釋)為:
如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內(nèi)部函數(shù)就被認(rèn)為是閉包(closure)。

  • 閉包=函數(shù)+引用環(huán)境
  • 閉包中是不能修改外部作用域的局部變量的
  • 當(dāng)閉包執(zhí)行完后,仍然能夠保持住當(dāng)前的運行環(huán)境
  • 閉包可以根據(jù)外部作用域的局部變量來得到不同的結(jié)果

裝飾器說明

裝飾器本質(zhì)上是一個Python函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能
裝飾器的返回值也是一個函數(shù)對象。
它經(jīng)常用于有切面需求的場景,比如:插入日志、性能測試、事務(wù)處理、緩存、權(quán)限校驗等場景。
裝飾器是解決這類問題的絕佳設(shè)計,有了裝飾器,我們就可以抽離出大量與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。

裝飾器的作用就是為已經(jīng)存在的函數(shù)或?qū)ο筇砑宇~外的功能

裝飾器/修飾符 - decorator

裝飾器知識

函數(shù)裝飾器

參考鏈接:
https://www.cnblogs.com/cicaday/p/python-decorator.html

概括的講,裝飾器的作用就是為已經(jīng)存在的函數(shù)或?qū)ο筇砑宇~外的功能

簡單裝飾器樣例

def debug(func):
    def wrapper(*args, **kwargs):  # 指定宇宙無敵參數(shù)
        print "[DEBUG]: enter {}()".format(func.__name__)
        print 'Prepare and say...',
        return func(*args, **kwargs)
    return wrapper  # 返回

@debug
def say(something):
    print "hello {}!".format(something)
   
等同于 
say = debug(say)

原理分析

@decorator_a
def f():
    pass
等價于
f = decorator_a(f)

裝飾器滿足的條件

  1. 裝飾器函數(shù)運行在函數(shù)定義的時候
  2. 裝飾器需要返回一個可執(zhí)行的對象
  3. 裝飾器返回的可執(zhí)行對象要兼容函數(shù)f的參數(shù)

類裝飾器

類裝飾器中必須使用 __call__ 方法。將類實例轉(zhuǎn)為可調(diào)用對象。

class Decorator(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print("decorator start")
        self.f()
        print("decorator end")

@Decorator
def func():
    print("func")

func()

這里有注意的是:call()是一個特殊方法,它可將一個類實例變成一個可調(diào)用對象:

p = Decorator(func) # p是類Decorator的一個實例
p() # 實現(xiàn)了__call__()方法后,p可以被調(diào)用

要使用類裝飾器必須實現(xiàn)類中的call()方法,就相當(dāng)于將實例變成了一個方法。

裝飾器鏈

所謂裝飾器鏈,即多個裝飾器的解析方式。

@decorator_b
@decorator_a
def test():
    pass
等同于
test = decorator_b(decorator_a(test))

裝飾器執(zhí)行順序 是從近到遠依次執(zhí)行。

內(nèi)置裝飾器

內(nèi)置裝飾器

  • 特性(property)
  • 靜態(tài)方法(staticmethod)
  • 類方法(classmethod)

內(nèi)置裝飾器參考鏈接

附錄A-裝飾器庫參數(shù)表

官方functools文檔
functools參考博客

functools,用于高階函數(shù):
指那些作用于函數(shù)或者返回其它函數(shù)的函數(shù),通常只要是可以被當(dāng)做函數(shù)調(diào)用的對象就是這個模塊的目標(biāo)。

functools方法

  • cmp_to_key,將一個比較函數(shù)轉(zhuǎn)換關(guān)鍵字函數(shù);
  • partial,針對函數(shù)起作用,并且是部分的;
  • reduce,與python內(nèi)置的reduce函數(shù)功能一樣;
  • total_ordering,在類裝飾器中按照缺失順序,填充方法;
  • update_wrapper,更新一個包裹(wrapper)函數(shù),使其看起來更像被包裹(wrapped)的函數(shù);
  • wraps,可用作一個裝飾器,簡化調(diào)用update_wrapper的過程;

cmp_to_key
將老式的比較函數(shù)(comparison function)轉(zhuǎn)換為關(guān)鍵字函數(shù)(key function),與接受key function的工具一同使用(例如sorted,min,max,heapq.nlargest,itertools.groupby),該函數(shù)主要用于將程序轉(zhuǎn)換成Python 3格式的,因為Python 3中不支持比較函數(shù)。比較函數(shù)是可調(diào)用的,接受兩個參數(shù),比較這兩個參數(shù)并根據(jù)他們的大小關(guān)系返回負值、零或者正值中的一個。關(guān)鍵字函數(shù)也是可調(diào)用的,接受一個參數(shù),同時返回一個可以用作排序關(guān)鍵字的值。
partial
functools.partial(func, *args, **keywords),函數(shù)裝飾器,返回一個新的partial對象。調(diào)用partial對象和調(diào)用被修飾的函數(shù)func相同,只不過調(diào)用partial對象時傳入的參數(shù)個數(shù)通常要少于調(diào)用func時傳入的參數(shù)個數(shù)。
reduce
與Python內(nèi)置的reduce函數(shù)一樣,為了向Python3過渡
total_ordering
這是一個類裝飾器,給定一個類,這個類定義了一個或者多個比較排序方法,這個類裝飾器將會補充其余的比較方法,減少了自己定義所有比較方法時的工作量.
被修飾的類必須至少定義 lt(), le(),gt(),ge()中的一個,同時,被修飾的類還應(yīng)該提供 eq()方法。
update_wrapper
更新一個包裹(wrapper)函數(shù),使其看起來更像被包裹(wrapped)的函數(shù)。
wraps
這個函數(shù)可用作一個裝飾器,簡化調(diào)用update_wrapper的過程,調(diào)用這個函數(shù)等價于調(diào)用partial(update_wrapper, wrapped = wrapped, assigned = assigned,updated = updated)。

附錄B-測試代碼樣例

文件: /home/scfan/pro/server/pro/tools/base_decorator.py

import time
import datetime
import functools

def decorator_func(text="all"):
    u""" 統(tǒng)計函數(shù)相關(guān)信息 All
    - 函數(shù)運行時間
    - 函數(shù)名稱

    """
    def decorator(func,*args,**kwargs):
        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            start = datetime.datetime.now()
            data = func(*args, **kwargs)
            runtime = datetime.datetime.now() - start
            msg = "@函數(shù)運行信息: 函數(shù)類型[%s],函數(shù)名稱[%s],運行時間[%s秒]"%(text,func.__name__,runtime.total_seconds())
            print(msg)
            return data
        return wrapper
    return decorator

class Decorator(object):
    u"""
        裝飾器類
    """
    def __init__(self, func):
        self.func = func

    # __call__()是一個特殊方法,它可將一個類實例變成一個可調(diào)用對象
    def __call__(self, *args, **kwargs):
        print("decorator start")
        self.func()
        print("decorator end")
 
 if __name__ == '__main__':
    @Decorator
    @decorator_func("all")
    def a(b="cc"):
        for i in range(2):
            time.sleep(1)
        print "函數(shù)運行...."
        return b
    a()      

運行信息

(env) [scfan@WOM tools]$ python base_decorator.py 
decorator start
函數(shù)運行....
@函數(shù)運行信息: 函數(shù)類型[all],函數(shù)名稱[a],運行時間[2.004331秒]
decorator end

附錄C-參考資源鏈接

附錄D-裝飾器相關(guān)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容