国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python深入學習之裝飾器

2019-11-25 18:14:43
字體:
來源:轉載
供稿:網友

裝飾器(decorator)是一種高級Python語法。裝飾器可以對一個函數、方法或者類進行加工。在Python中,我們有多種方法對函數和類進行加工,比如在Python閉包中,我們見到函數對象作為某一個函數的返回結果。相對于其它方式,裝飾器語法簡單,代碼可讀性高。因此,裝飾器在Python項目中有廣泛的應用。

裝飾器最早在Python 2.5中出現,它最初被用于加工函數和方法這樣的可調用對象(callable object,這樣的對象定義有__call__方法)。在Python 2.6以及之后的Python版本中,裝飾器被進一步用于加工類。

裝飾函數和方法

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

復制代碼 代碼如下:

# get square sum
def square_sum(a, b):
    return a**2 + b**2

# get square diff
def square_diff(a, b):
    return a**2 - b**2

print(square_sum(3, 4))
print(square_diff(3, 4))

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

復制代碼 代碼如下:

# modify: print input

# get square sum
def square_sum(a, b):
    print("intput:", a, b)
    return a**2 + b**2

# get square diff
def square_diff(a, b):
    print("input", a, b)
    return a**2 - b**2

print(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
@decorator
def square_sum(a, b):
    return a**2 + b**2

# get square diff
@decorator
def square_diff(a, b):
    return a**2 - b**2

print(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 layer
def 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**2

print(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

@decorator
class 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的次數了。

總結

裝飾器的核心作用是name binding。這種語法是Python多編程范式的又一個體現。大部分Python用戶都不怎么需要定義裝飾器,但有可能會使用裝飾器。鑒于裝飾器在Python項目中的廣泛使用,了解這一語法是非常有益的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 涟源市| 原阳县| 厦门市| 包头市| 太谷县| 左贡县| 扶风县| 蒙山县| 平安县| 固始县| 霍山县| 封开县| 德钦县| 佛冈县| 东乡| 孙吴县| 南丹县| 东光县| 陈巴尔虎旗| 潼关县| 衡南县| 奎屯市| 日喀则市| 榆社县| 江门市| 汾西县| 田林县| 五大连池市| 彭州市| 洛南县| 五台县| 娄底市| 墨江| 宁远县| 云梦县| 丹巴县| 西乌珠穆沁旗| 桦南县| 栖霞市| 正安县| 涿鹿县|