中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python?Decorator的設計模式實例分析

發布時間:2022-07-06 09:23:34 來源:億速云 閱讀:120 作者:iii 欄目:開發技術

本篇內容介紹了“Python Decorator的設計模式實例分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

關于代理模式、裝飾模式

設計模式中經常提到的代理模式、裝飾模式,這兩種叫法實際上是說的同一件事,只是側重點有所不同而已。

這兩者都是通過在原有對象的基礎上封裝一層對象,通過調用封裝后的對象而不是原來的對象來實現代理/裝飾的目的。

例如:(以Java為例)

public class CountProxy implements Count {
    private CountImpl countImpl;
    public CountProxy(CountImpl countImpl) {
        this.countImpl = countImpl;
    }
    @Override
    public void queryCount() {  
        System.out.println("事務處理之前");
        // 調用委托類的方法;
        countImpl.queryCount();
        System.out.println("事務處理之后");
    }
    @Override
    public void updateCount() {
        System.out.println("事務處理之前");
        // 調用委托類的方法;
        countImpl.updateCount();
        System.out.println("事務處理之后");
    }
}

在這個例子中CountProxy是對CountImpl的封裝。

使用者通過CountProxy.queryCount方法來調用CountImpl.queryCount方法,這被稱為代理,即CountProxy是代理類,CountImpl是被代理類。

CountProxy.queryCount方法中,可以在CountImpl.queryCount方法調用之前和之后添加一些額外的操作,被稱為裝飾,即CountProxy是裝飾類,CountImpl是被裝飾類。

如果強調通過CountProxy 對CountImpl進行代理的作用,則稱為代理模式;

如果強調通過CountProxy 對CountImpl增加額外的操作,則稱為裝飾模式;

不論是哪種稱呼,其本質都在于對原有對象的封裝。

其封裝的目的在于增強所封裝對象的功能或管理所封裝的對象。

從上面的例子也可以發現,代理/封裝所圍繞的核心是可調用對象(比如函數)。

Python中的代理/裝飾

Python中的可調用對象包括函數、方法、實現了__call__方法的類。

Python中的函數也是對象,可以作為高階函數的參數傳入或返回值返回。

因此,當代理/裝飾的對象是函數時,可以使用高階函數來對某個函數進行封裝。

例如:

def query_count_proxy(fun, name, age):
    print('do something before')
    rv = fun(name, age)
    print('do something after')
    return rv
def query_count(name, age):
    print('name is %s, age is %d' % (name, age))
query_count_proxy(query_count, 'Lee', 20)

但是,這個例子中,query_count函數作為參數傳入query_count_proxy函數中,并在query_count_proxy函數中被調用,其結果作為返回值返回。這就完成了代理的功能,同時,在調用query_count函數的前后,我們還增加了裝飾代碼。

但是,query_count_proxy的函數參數與query_count不一樣了,理想的代理應該保持接口一致才對。

為了保持一致,我們可以利用高階函數可以返回函數的特點來完成:

def query_count_proxy(fun):
    def wrapper(name, age):
        print('do something before')
        rv = fun(name, age)
        print('do something after')
        return rv
    return wrapper
def query_count(name, age):
    print('name is %s, age is %d' % (name, age))
query_count_proxy(query_count)('Lee', 20)

修改后的例子,query_count_proxy僅負責接受被代理的函數query_count作為參數,同時,返回一個函數對象wrapper作為返回值,真正的封裝動作在wrapper這個函數中完成。

此時,如果調用query_count_proxy(query_count)就得到了wrapper函數對象,則,執行query_count_proxy(query_count)('Lee', 20)就相當于執行了wrapper('Lee', 20)

但是可以看到,query_count_proxy(query_count)('Lee', 20)這種使用方法,仍然不能保證一致。

為了保持一致,我們需要利用Python中對象與其名稱可以動態綁定的特點。不使用query_count_proxy(quer_count)('Lee', 20)來調用代理函數,而是使用下面兩句:

query_count = query_count_proxy(query_count)
query_count('Lee', 20)

執行query_count_proxy(query_count)生成wrapper函數對象,將這個對象通過query_count = query_count_proxy(query_count)綁定到query_count這個名字上來,這樣執行query_count('Lee', 20)時,其實執行的是wrapper('Lee', 20)

這么做的結果就是:使用代理時調用query_count('Lee', 20)與不使用代理時調用query_count('Lee', 20)對使用者而言保持不變,不用改變代碼,但是在真正執行時,使用的是代理/裝飾后的函數。

這里,基本利用Python的高階函數及名稱綁定完成了代理/裝飾的功能。

還有什么不理想的地方呢?

對,就是query_count = query_count_proxy(query_count),因為這句既不簡潔,又屬于重復工作。

Python為我們提供了語法糖來完成這類的tedious work。

方法就是:

@query_count_proxy
def query_count(name, age):
    return 'name is %s, age is %d' % (name, age)

query_count = query_count_proxy(query_count)就等同于在定義query_count函數的時候,在其前面加上@query_count_proxy

Python看到這樣的語法,就會自動的執行query_count = query_count_proxy(query_count)進行name rebinding

“Python Decorator的設計模式實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浦县| 鞍山市| 祁阳县| 南涧| 大邑县| 从化市| 松原市| 伽师县| 修武县| 图们市| 沁水县| 紫阳县| 昌黎县| 登封市| 叶城县| 前郭尔| 金华市| 樟树市| 綦江县| 通海县| 炉霍县| 贵阳市| 宜州市| 左贡县| 呈贡县| 蕉岭县| 阿城市| 霸州市| 苗栗市| 彭山县| 怀远县| 金坛市| 壶关县| 靖边县| 安图县| 聂拉木县| 电白县| 板桥市| 土默特右旗| 江津市| 辛集市|