[Python入門及進階筆記]Python-decorator裝飾器小結__Python

來源:互聯網
上載者:User

http://blog.csdn.net/wklken/article/details/8118942


-----------------------------------------------

想找個地方快樂的coding,貌似不是一件容易的事情。

一時衝動,不過後路已斷,做自己想做的事情,總要付出一些代價的,堅持吧,只能。

吐槽下,本周各種事情,搞得如越級打怪般艱難。周六,去三小時,回來三小時,大敗而歸,但是還是學到不少東西。

差距還是有的,雖然自信可以在最短時間補上,但是,需要成本。

總之,貌似時機不對,哎以上廢話,進入正題

上周六碰到了,一周忙碌,今天稍微理下,待補全,資料主要來源於書籍,網路&self.coding()。有任何問題,請指正哈 基本概念

具體概念自己google

裝飾器是一個很著名的設計模式,經常被用於有切面需求的情境,較為經典的有插入日誌、效能測試、交易處理, Web許可權校正, Cache等。

很有名的例子,就是咖啡,加糖的咖啡,加牛奶的咖啡。本質上,還是咖啡,只是在原有的東西上,做了“裝飾”,使之附加一些功能或特性。

例如記錄日誌,需要對某些函數進行記錄

笨的辦法,每個函數加入代碼,如果代碼變了,就悲催了

裝飾器的辦法,定義一個專門日誌記錄的裝飾器,對需要的函數進行裝飾,搞定 優點

抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用

即,可以將函數“修飾”為完全不同的行為,可以有效將商務邏輯正交分解,如用於將許可權和身分識別驗證從業務中獨立出來

概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能 Python中的裝飾器

在Python中,裝飾器實現是十分方便的

原因是:函數可以被扔來扔去。

函數作為一個對象:

A.可以被賦值給其他變數,可以作為傳回值B.可以被定義在另外一個函數內

def:

裝飾器是一個函數,一個用來封裝函數的函數,裝飾器在函數申明完成的時候被調用,調用之後返回一個修改之後的函數對象,將其重新賦值原來的標識符,並永久喪失對原始函數對象的訪問(申明的函數被換成一個被裝飾器裝飾過後的函數)

當我們對某個方法應用了裝飾方法後, 其實就改變了被裝飾函數名稱所引用的函數代碼塊進入點,使其重新指向了由裝飾方法所返回的函數進入點。

由此我們可以用decorator改變某個原有函數的功能,添加各種操作,或者完全改變原有實現 分類:

裝飾器分為無參數decorator,有參數decorator

* 無參數decorator產生一個新的裝飾器函數* 有參decorator有參裝飾,裝飾函數先處理參數,再產生一個新的裝飾器函數,然後對函數進行裝飾

裝飾器有參/無參,函數有參/無參,組合共4種 具體定義:

decorator方法

A.把要裝飾的方法作為輸入參數,

B.在函數體內可以進行任意的操作(可以想象其中蘊含的威力強大,會有很多應用情境),

C.只要確保最後返回一個可執行檔函數即可(可以是原來的輸入參數函數, 或者是一個新函數) 無參數裝飾器 – 封裝無參數函數

不需要針對參數進行處理和最佳化

def decorator(func):    print "hello"    return func@decoratordef foo():    passfoo()

foo()等價於:

foo = decorator(foo)foo()
無參數裝飾器 – 封裝帶參數函數
def decorator_func_args(func):    def handle_args(*args, **kwargs): #處理傳入函數的參數        print "begin"        func(*args, **kwargs)   #函數調用        print "end"    return handle_args@decorator_func_argsdef foo2(a, b=2):    print a, bfoo2(1)

foo2(1)等價於

foo2 = decorator_func_args(foo2)foo2(1)
帶參數裝飾器 – 封裝無參數函數
def decorator_with_params(arg_of_decorator):#這裡是裝飾器的參數    print arg_of_decorator    #最終被返回的函數    def newDecorator(func):         print func        return func    return newDecorator@decorator_with_params("deco_args")def foo3():    passfoo3()

與前面的不同在於:比上一層多了一層封裝,先傳遞參數,再傳遞函數名

第一個函數decomaker是裝飾函數,它的參數是用來加強“加強裝飾”的。由於此函數並非被裝飾的函數對象,所以在內部必須至少建立一個接受被裝飾函數的函數,然後返回這個對象(實際上此時foo3= decorator_with_params(arg_of_decorator)(foo3)) 帶參數裝飾器– 封裝帶參數函數

def decorator_whith_params_and_func_args(arg_of_decorator):    def handle_func(func):        def handle_args(*args, **kwargs):            print "begin"            func(*args, **kwargs)            print "end"            print arg_of_decorator, func, args,kwargs        return handle_args    return handle_func@decorator_whith_params_and_func_args("123")def foo4(a, b=2):    print "Content"foo4(1, b=3)
內建裝飾器

內建的裝飾器有三個:staticmethod,classmethod, property

class A():    @staticmethod    def test_static():        print "static"    def test_normal(self):        print "normal"    @classmethod    def test_class(cls):        print "class", clsa = A()A.test_static()a.test_static()a.test_normal()a.test_class()

結果:

staticstaticnormalclass __main__.A

A.test_static

staticmethod 類中定義的執行個體方法變成靜態方法

基本上和一個全域函數差不多(不需要傳入self,只有一般的參數),只不過可以通過類或類的執行個體對象來調用,不會隱式地傳入任何參數。

類似於靜態語言中的靜態方法

B.test_normal

普通對象方法:普通對象方法至少需要一個self參數,代表類對象執行個體

C.test_class

類中定義的執行個體方法變成類方法

classmethod需要傳入類對象,可以通過執行個體和類對象進行調用。

是和一個class相關的方法,可以通過類或類執行個體調用,並將該class對象(不是class的執行個體對象)隱式地當作第一個參數傳入。

就這種方法可能會 比較奇怪一點,不過只要你搞清楚了python裡class也是個真實地存在於記憶體中的對象,而不是靜態語言中只存在於編譯期間的類型,就好辦了。正常的方法就是和一個類的執行個體對象相關的方法,通過類執行個體對象進行調用,並將該執行個體對象隱式地作為第一個參數傳入,這個也和其它語言比較像。

D.區別

staticmethod,classmethod相當於全域方法,一般用在抽象類別或父類中。一般與具體的類無關。

類方法需要額外的類變數cls,當有子類繼承時,調用類方法傳入的類變數cls是子類,而不是父類。

類方法和靜態方法都可以通過類對象和類的執行個體對象訪問

定義方式,傳入的參數,調用方式都不相同。

E.property

對類屬性的操作,類似於java中定義getter/setter

class B():    def __init__(self):        self.__prop = 1    @property    def prop(self):        print "call get"        return self.__prop    @prop.setter    def prop(self, value):        print "call set"        self.__prop = value    @prop.deleter    def prop(self):        print "call del"        del self.__prop
其他

A.裝飾器的順序很重要,需要注意

@A@B@Cdef f ():

等價於

f = A(B(C(f)))

B.decorator的作用對象可以是模組層級的方法或者類方法

C.functools模組提供了兩個裝飾器。這個模組是Python 2.5後新增的。

functools.wraps(func)total_ordering(cls)這個具體自己去看吧,後續用到了再補充 一個簡單例子

通過一個變數,控制調用函數時是否統計時間

#!/usr/bin/env python# -*- coding:utf-8 -*-#@author: wklken@yeah.net#@version: a test of decorator#@date: 20121027#@desc: just a testimport loggingfrom time import timelogger = logging.getLogger()logger.setLevel(logging.DEBUG)is_debug = Truedef count_time(is_debug):    def  handle_func(func):        def  handle_args(*args, **kwargs):            if is_debug:                begin = time()                func(*args, **kwargs)                logging.debug( "[" + func.__name__ + "] -> " + str(time() - begin) )            else:                func(*args, **kwargs)        return handle_args    return handle_funcdef pr():    for i in range(1,1000000):        i = i * 2    print "hello world"def test():    pr()@count_time(is_debug)def test2():    pr()@count_time(False)def test3():    pr()if __name__ == "__main__":    test()    test2()    test3()

結果:

hello worldhello worldDEBUG:root:[test2] -> 0.0748538970947hello world

The end!

wklken

Gighub: https://github.com/wklken

Blog: http://wklken.sinaapp.com/

2012-10-27

轉載請註明出處,謝謝!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.