Python-02進階-02裝飾器

Python-00裝飾器

裝飾器


TODO

總結

裝飾器的作用就是爲已經存在的函數或對象添加額外的功能

裝飾器使用種類:

  • 函數裝飾器
  • 類裝飾器
  • 函數裝飾器裝飾 類
  • 類裝飾器裝飾 函數

裝飾器樣例

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

默認裝飾器函數

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

裝飾器庫 functools
因爲使用裝飾器 functools 會導致函數或類信息缺失。
例如 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

裝飾器&函數

函數簡單說明

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

瞭解裝飾器之前也需要了解內部函數與函數閉包

參考鏈接: 內部函數&函數閉包

內部函數

def wai_hanshu(canshu_1):

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

  return nei_hanshu  # 我將內部函數返回出去

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

閉包說明
參考鏈接: 函數閉包
python中的閉包從表現形式上定義(解釋)爲:
如果在一個內部函數裏,對在外部作用域(但不是在全局作用域)的變量進行引用,那麼內部函數就被認爲是閉包(closure)。

  • 閉包=函數+引用環境
  • 閉包中是不能修改外部作用域的局部變量的
  • 當閉包執行完後,仍然能夠保持住當前的運行環境
  • 閉包可以根據外部作用域的局部變量來得到不同的結果

裝飾器說明

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

裝飾器的作用就是爲已經存在的函數或對象添加額外的功能

裝飾器/修飾符 - decorator

裝飾器知識

函數裝飾器

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

概括的講,裝飾器的作用就是爲已經存在的函數或對象添加額外的功能

簡單裝飾器樣例

def debug(func):
    def wrapper(*args, **kwargs):  # 指定宇宙無敵參數
        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. 裝飾器函數運行在函數定義的時候
  2. 裝飾器需要返回一個可執行的對象
  3. 裝飾器返回的可執行對象要兼容函數f的參數

類裝飾器

類裝飾器中必須使用 __call__ 方法。將類實例轉爲可調用對象。

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()是一個特殊方法,它可將一個類實例變成一個可調用對象:

p = Decorator(func) # p是類Decorator的一個實例
p() # 實現了__call__()方法後,p可以被調用

要使用類裝飾器必須實現類中的__call__()方法,就相當於將實例變成了一個方法。

裝飾器鏈

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

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

裝飾器執行順序 是從近到遠依次執行

內置裝飾器

內置裝飾器

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

內置裝飾器參考鏈接

附錄A-裝飾器庫參數表

官方functools文檔
functools參考博客

functools,用於高階函數:
指那些作用於函數或者返回其它函數的函數,通常只要是可以被當做函數調用的對象就是這個模塊的目標。

functools方法

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

cmp_to_key
將老式的比較函數(comparison function)轉換爲關鍵字函數(key function),與接受key function的工具一同使用(例如sorted,min,max,heapq.nlargest,itertools.groupby),該函數主要用於將程序轉換成Python 3格式的,因爲Python 3中不支持比較函數。比較函數是可調用的,接受兩個參數,比較這兩個參數並根據他們的大小關係返回負值、零或者正值中的一個。關鍵字函數也是可調用的,接受一個參數,同時返回一個可以用作排序關鍵字的值。
partial
functools.partial(func, *args, **keywords),函數裝飾器,返回一個新的partial對象。調用partial對象和調用被修飾的函數func相同,只不過調用partial對象時傳入的參數個數通常要少於調用func時傳入的參數個數。
reduce
與Python內置的reduce函數一樣,爲了向Python3過渡
total_ordering
這是一個類裝飾器,給定一個類,這個類定義了一個或者多個比較排序方法,這個類裝飾器將會補充其餘的比較方法,減少了自己定義所有比較方法時的工作量.
被修飾的類必須至少定義 lt(), le(),gt(),ge()中的一個,同時,被修飾的類還應該提供 eq()方法。
update_wrapper
更新一個包裹(wrapper)函數,使其看起來更像被包裹(wrapped)的函數。
wraps
這個函數可用作一個裝飾器,簡化調用update_wrapper的過程,調用這個函數等價於調用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""" 統計函數相關信息 All
    - 函數運行時間
    - 函數名稱

    """
    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 = "@函數運行信息: 函數類型[%s],函數名稱[%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__()是一個特殊方法,它可將一個類實例變成一個可調用對象
    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 "函數運行...."
        return b
    a()      

運行信息

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

附錄C-參考資源鏈接

附錄D-裝飾器相關

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