對Python裝飾器的個人理解方法

來源:互聯網
上載者:User

標籤:python   函數   裝飾器   執行過程   

0.說明

         

        在自己好好總結並對Python裝飾器的執行過程進行分解之前,對於裝飾器雖然理解它的基本工作方式,但對於存在複雜參數的裝飾器(裝飾器和函數本身都有參數),總是會感到很模糊,即使這會弄懂了,下一次也很快忘記,其實本質上還是沒有多花時間去搞懂其中的細節問題。

        雖然網路上已經有很多這樣的文章,但顯然都是別人的思想,因此自己總是記不牢,所以花點時間自己好好整理一下。

        最近在對《Python核心編程》做總結,收穫了不少,下面分享一下我自己對於Python裝飾器的理解,後面還提供了一個較為複雜的Python裝飾器的執行過程的分解,可以參考一下。



1.Python裝飾器的出現


         在沒有裝飾器之前,如果要在類中定義一個靜態方法,需要使用下面的方法:

class MyClass(object):    def staticFoo():        staticFoo = staticmethod(staticFoo)

        即要在該靜態方法中加入類似staticmethod()內建函數將該方法轉換為靜態方法,這顯然非常麻煩,而有了裝飾器之後,就可以寫成下面這樣:

class MyClass(object):    @staticmethod    def staticFoo():        pass

        這樣就簡潔很多了。



2.Python裝飾器類型與理解


(1)無參數裝飾器    

  • 一個裝飾器

        下面的情況:

@fdef foo():    pass

        其實就相當於:

def foo():    passfoo = g(foo)
  • 多個裝飾器

        下面的情況:

@g@fdef foo():    pass

        就相當於:

def foo():    passfoo = g(f(foo))


(2)含參數裝飾器

  • 帶有參數的一個裝飾器

        下面的情況:

@decomaker(deco_args)def foo():    pass

        就相當於:

def foo():    passfoo = decomaker(deco_args)(foo)

        用這樣的思想去理解就非常好理解了:decomaker()用deco_args做了些事並返回函數對象,而該函數對象正是以foo作為其參數的裝飾器。

        下面多個裝飾器的例子也是按這樣的思想去理解。

  • 帶有參數的多個裝飾器

        下面的情況:

@deco1(deco_arg)@deco2()def foo():    pass

        就相當於:

def foo():    passfoo = deco1(deco_arg)(deco2(foo))



3.Python裝飾器執行過程的手動分解


        OK,有了上面的理論基礎,理解下面一個較為複雜的裝飾器就很容易了:

from functools import wrapsdef log(text):    def decorator(func):        @wraps(func)                    #it works like:wraper.__name__ = func.__name__        def wrapper(*args, **kwargs):            print ‘%s %s():‘ % (text, func.__name__)            return func(*args, **kwargs)        return wrapper    return decorator@log(‘Hello‘)def now(area):    print area, ‘2016-01-23‘    now(‘Beijing‘)print ‘The name of function now() is:‘, now.__name__

        執行如下:

/usr/bin/python2.7 /home/xpleaf/PycharmProjects/decorator_test/dec10.pyHello now():Beijing 2016-01-23The name of function now() is: now

對於該程式的執行過程,可以分析如下:

1.先執行log(‘Hello‘)函數,此時返回了一個新的函數,只不過其中的text變數被替換為‘Hello‘,所以用來裝飾now函數的新的裝飾器如下:

def decorator(func):    @wraps(func)                    #it works like:wraper.__name__ = func.__name__    def wrapper(*args, **kwargs):        print ‘%s %s():‘ % (‘Hello‘, func.__name__)        return func(*args, **kwargs)    return wrapper

2.所以此時的now函數,就相當於:

now = decorator(now)

3.即now就相當於:

def now(*args, **kwargs):    print ‘%s %s():‘ % (‘Hello‘, old_now.__name__)    return old_now(*args, **kwargs)# 現在的函數名稱變為了now而不是wrapper,是因為使用了wraps裝飾器

   所以,輸出的結果也就非常好理解了。

        關於wraps,它也是一個裝飾器,使用它的作用是,被我們用自訂裝飾器修改後的函數,它的函數名稱,即func.__name__跟原來是一樣的,而它的工作原理正如上面所提及的,即:

wraper.__name__ = func.__name__

        也就是說,使用wraps可以不改變原來函數的屬性,當然,上面只是簡單說明了一下其工作原理,詳細的可以參考wraps的原始碼。

        在GitHub上給出了10個理解裝飾器的例子,可以參考一下:https://github.com/xpleaf/decorator


        本文選中我的《Python回顧與整理》系列博文中的《Python回顧與整理9:函數和函數式編程》


本文出自 “香飄葉子” 部落格,請務必保留此出處http://xpleaf.blog.51cto.com/9315560/1763567

對Python裝飾器的個人理解方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.