Python編程中裝飾器的使用樣本解析

來源:互聯網
上載者:User
裝飾函數和方法

我們先定義兩個簡單的數學函數,一個用來計算平方和,一個用來計算平方差:

# get square sumdef square_sum(a, b):  return a**2 + b**2# get square diffdef square_diff(a, b):  return a**2 - b**2print(square_sum(3, 4))print(square_diff(3, 4))

在擁有了基本的數學功能之後,我們可能想為函數增加其它的功能,比如列印輸入。我們可以改寫函數來實現這一點:

# modify: print input# get square sumdef square_sum(a, b):  print("intput:", a, b)  return a**2 + b**2# get square diffdef square_diff(a, b):  print("input", a, b)  return a**2 - b**2print(square_sum(3, 4))print(square_diff(3, 4))

我們修改了函數的定義,為函數增加了功能。

現在,我們使用裝飾器來實現上述修改:

def decorator(F):  def new_F(a, b):    print("input", a, b)    return F(a, b)  return new_F# get square sum@decoratordef square_sum(a, b):  return a**2 + b**2# get square diff@decoratordef square_diff(a, b):  return a**2 - b**2print(square_sum(3, 4))print(square_diff(3, 4))

裝飾器可以用def的形式定義,如上面代碼中的decorator。裝飾器接收一個可調用對象作為輸入參數,並返回一個新的可調用對象。裝飾器建立了一個可調用對象,也就是上面的new_F。new_F中,我們增加了列印的功能,並通過調用F(a, b)來實現原有函數的功能。

定義好裝飾器後,我們就可以通過@文法使用了。在函數square_sum和square_diff定義之前調用@decorator,我們實際上將square_sum或square_diff傳遞給decorator,並將decorator返回的新的可調用對象賦給原來的函數名(square_sum或square_diff)。 所以,當我們調用square_sum(3, 4)的時候,就相當於:

square_sum = decorator(square_sum)square_sum(3, 4)

我們知道,Python中的變數名和對象是分離的。變數名可以指向任意一個對象。從本質上,裝飾器起到的就是這樣一個重新指向變數名的作用(name binding),讓同一個變數名指向一個新返回的可調用對象,從而達到修改可調用對象的目的。

與加工函數類似,我們可以使用裝飾器加工類的方法。

如果我們有其他的類似函數,我們可以繼續調用decorator來修飾函數,而不用重複修改函數或者增加新的封裝。這樣,我們就提高了程式的可重複利用性,並增加了程式的可讀性。

含參的裝飾器

在上面的裝飾器調用中,比如@decorator,該裝飾器預設它後面的函數是唯一的參數。裝飾器的文法允許我們調用decorator時,提供其它參數,比如@decorator(a)。這樣,就為裝飾器的編寫和使用提供了更大的靈活性。

# a new wrapper layerdef pre_str(pre=''):  # old decorator  def decorator(F):    def new_F(a, b):      print(pre + "input", a, b)      return F(a, b)    return new_F  return decorator# get square sum@pre_str('^_^')def square_sum(a, b):  return a**2 + b**2# get square diff@pre_str('T_T')def square_diff(a, b):  return a**2 - b**2print(square_sum(3, 4))print(square_diff(3, 4))

上面的pre_str是允許參數的裝飾器。它實際上是對原有裝飾器的一個函數封裝,並返回一個裝飾器。我們可以將它理解為一個含有環境參量的閉包。當我們使用@pre_str('^_^')調用的時候,Python能夠發現這一層的封裝,並把參數傳遞到裝飾器的環境中。該調用相當於:

square_sum = pre_str('^_^') (square_sum)

裝飾類

在上面的例子中,裝飾器接收一個函數,並返回一個函數,從而起到加工函數的效果。在Python 2.6以後,裝飾器被拓展到類。一個裝飾器可以接收一個類,並返回一個類,從而起到加工類的效果。

def decorator(aClass):  class newClass:    def __init__(self, age):      self.total_display  = 0      self.wrapped     = aClass(age)    def display(self):      self.total_display += 1      print("total display", self.total_display)      self.wrapped.display()  return newClass@decoratorclass Bird:  def __init__(self, age):    self.age = age  def display(self):    print("My age is",self.age)eagleLord = Bird(5)for i in range(3):  eagleLord.display()

在decorator中,我們返回了一個新類newClass。在新類中,我們記錄了原來類產生的對象(self.wrapped),並附加了新的屬性total_display,用於記錄調用display的次數。我們也同時更改了display方法。

通過修改,我們的Bird類可以顯示調用display的次數了。

  • 聯繫我們

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