亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Python Decorator的來龍

frank_fun / 3590人閱讀

摘要:中的函數(shù)也是對(duì)象,可以作為高階函數(shù)的參數(shù)傳入或返回值返回。因此,當(dāng)代理裝飾的對(duì)象是函數(shù)時(shí),可以使用高階函數(shù)來對(duì)某個(gè)函數(shù)進(jìn)行封裝。

引言

本文主要梳理了Python decorator的實(shí)現(xiàn)思路,解釋了為什么Python decorator是現(xiàn)在這個(gè)樣子。

關(guān)于代理模式、裝飾模式

設(shè)計(jì)模式中經(jīng)常提到的代理模式、裝飾模式,這兩種叫法實(shí)際上是說的同一件事,只是側(cè)重點(diǎn)有所不同而已。

這兩者都是通過在原有對(duì)象的基礎(chǔ)上封裝一層對(duì)象,通過調(diào)用封裝后的對(duì)象而不是原來的對(duì)象來實(shí)現(xiàn)代理/裝飾的目的。

例如:(以Java為例)

public class CountProxy implements Count {
    private CountImpl countImpl;

    public CountProxy(CountImpl countImpl) {
        this.countImpl = countImpl;
    }

    @Override
    public void queryCount() {  
        System.out.println("事務(wù)處理之前");
        // 調(diào)用委托類的方法;
        countImpl.queryCount();
        System.out.println("事務(wù)處理之后");
    }

    @Override
    public void updateCount() {
        System.out.println("事務(wù)處理之前");
        // 調(diào)用委托類的方法;
        countImpl.updateCount();
        System.out.println("事務(wù)處理之后");

    }

}

在這個(gè)例子中CountProxy是對(duì)CountImpl的封裝。
使用者通過CountProxy.queryCount方法來調(diào)用CountImpl.queryCount方法,這被稱為代理,即CountProxy是代理類,CountImpl是被代理類。
CountProxy.queryCount方法中,可以在CountImpl.queryCount方法調(diào)用之前和之后添加一些額外的操作,被稱為裝飾,即CountProxy是裝飾類,CountImpl是被裝飾類。

如果強(qiáng)調(diào)通過CountProxy 對(duì)CountImpl進(jìn)行代理的作用,則稱為代理模式;
如果強(qiáng)調(diào)通過CountProxy 對(duì)CountImpl增加額外的操作,則稱為裝飾模式;

不論是哪種稱呼,其本質(zhì)都在于對(duì)原有對(duì)象的封裝。
其封裝的目的在于增強(qiáng)所封裝對(duì)象的功能或管理所封裝的對(duì)象。

從上面的例子也可以發(fā)現(xiàn),代理/封裝所圍繞的核心是可調(diào)用對(duì)象(比如函數(shù))。

Python中的代理/裝飾

Python中的可調(diào)用對(duì)象包括函數(shù)、方法、實(shí)現(xiàn)了__call__方法的類。
Python中的函數(shù)也是對(duì)象,可以作為高階函數(shù)的參數(shù)傳入或返回值返回。
因此,當(dāng)代理/裝飾的對(duì)象是函數(shù)時(shí),可以使用高階函數(shù)來對(duì)某個(gè)函數(shù)進(jìn)行封裝。
例如:

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)

但是,這個(gè)例子中,query_count函數(shù)作為參數(shù)傳入query_count_proxy函數(shù)中,并在query_count_proxy函數(shù)中被調(diào)用,其結(jié)果作為返回值返回。這就完成了代理的功能,同時(shí),在調(diào)用query_count函數(shù)的前后,我們還增加了裝飾代碼。
但是,query_count_proxy的函數(shù)參數(shù)與query_count不一樣了,理想的代理應(yīng)該保持接口一致才對(duì)。

為了保持一致,我們可以利用高階函數(shù)可以返回函數(shù)的特點(diǎn)來完成:

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僅負(fù)責(zé)接受被代理的函數(shù)query_count作為參數(shù),同時(shí),返回一個(gè)函數(shù)對(duì)象wrapper作為返回值,真正的封裝動(dòng)作在wrapper這個(gè)函數(shù)中完成。

此時(shí),如果調(diào)用query_count_proxy(query_count)就得到了wrapper函數(shù)對(duì)象,則,執(zhí)行query_count_proxy(query_count)("Lee", 20)就相當(dāng)于執(zhí)行了wrapper("Lee", 20)

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

為了保持一致,我們需要利用Python中對(duì)象與其名稱可以動(dòng)態(tài)綁定的特點(diǎn)。
不使用query_count_proxy(quer_count)("Lee", 20)來調(diào)用代理函數(shù),而是使用下面兩句:

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

執(zhí)行query_count_proxy(query_count)生成wrapper函數(shù)對(duì)象,將這個(gè)對(duì)象通過query_count = query_count_proxy(query_count)綁定到query_count這個(gè)名字上來,這樣執(zhí)行query_count("Lee", 20)時(shí),其實(shí)執(zhí)行的是wrapper("Lee", 20)。

這么做的結(jié)果就是:使用代理時(shí)調(diào)用query_count("Lee", 20)與不使用代理時(shí)調(diào)用query_count("Lee", 20)對(duì)使用者而言保持不變,不用改變代碼,但是在真正執(zhí)行時(shí),使用的是代理/裝飾后的函數(shù)。

這里,基本利用Python的高階函數(shù)及名稱綁定完成了代理/裝飾的功能。
還有什么不理想的地方呢?
對(duì),就是query_count = query_count_proxy(query_count),因?yàn)檫@句既不簡(jiǎn)潔,又屬于重復(fù)工作。
Python為我們提供了語(yǔ)法糖來完成這類的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函數(shù)的時(shí)候,在其前面加上@query_count_proxy。

Python看到這樣的語(yǔ)法,就會(huì)自動(dòng)的執(zhí)行query_count = query_count_proxy(query_count)進(jìn)行name rebinding

補(bǔ)充

以上就是Python實(shí)現(xiàn)可調(diào)用對(duì)象裝飾的核心。
可調(diào)用對(duì)象包括函數(shù)、方法、實(shí)現(xiàn)了__call__方法的類,上述內(nèi)容只是針對(duì)函數(shù)來解釋,對(duì)于方法、實(shí)現(xiàn)了__call__方法的類,其基本原理相同,具體實(shí)現(xiàn)略有差別。

本文系作者原創(chuàng),如有轉(zhuǎn)載請(qǐng)注明出處。
由于水平精力有限,如有錯(cuò)誤歡迎指正。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/37596.html

相關(guān)文章

  • Python知識(shí)點(diǎn):理解和使用裝飾器 @decorator

    摘要:使用類裝飾器,優(yōu)點(diǎn)是靈活性大,高內(nèi)聚,封裝性。不過不用擔(dān)心,有,本身也是一個(gè)裝飾器,它的作用就是把原函數(shù)的元信息拷貝到裝飾器函數(shù)中,使得裝飾器函數(shù)也有和原函數(shù)一樣的元信息。 showImg(https://segmentfault.com/img/bVbrFWb?w=742&h=484);Python的裝飾器(decorator)是一個(gè)很棒的機(jī)制,也是熟練運(yùn)用Python的必殺技之一。...

    cyqian 評(píng)論0 收藏0
  • Python函數(shù)修飾器---當(dāng)方法前遇到@參數(shù)化修飾器方法時(shí)發(fā)生

    一、前提概念   Python中的函數(shù)是對(duì)象。也因此,函數(shù)可以被當(dāng)做變量使用。 二、代碼模型 以下代碼片段來自于: http://www.sharejs.com/codes/python/8361 # -*- coding: utf-8 -*- from threading import Thread import time class TimeoutEx...

    huashiou 評(píng)論0 收藏0
  • Python 裝飾器使用指南

    摘要:裝飾器是可調(diào)用的對(duì)象,其參數(shù)是另一個(gè)函數(shù)被裝飾的函數(shù)。第二大特性是,裝飾器在加載模塊時(shí)立即執(zhí)行。另一個(gè)常見的裝飾器是,它的作用是協(xié)助構(gòu)建行為良好的裝飾器。 裝飾器是可調(diào)用的對(duì)象,其參數(shù)是另一個(gè)函數(shù)(被裝飾的函數(shù))。 裝飾器基礎(chǔ)知識(shí) 首先看一下這段代碼 def deco(fn): print I am %s! % fn.__name__ @deco def func(): ...

    NeverSayNever 評(píng)論0 收藏0
  • Python 裝飾器執(zhí)行順序迷思

    摘要:探究多個(gè)裝飾器執(zhí)行順序裝飾器是用于封裝函數(shù)或代碼的工具,網(wǎng)上可以搜到很多文章可以學(xué)習(xí),我在這里要討論的是多個(gè)裝飾器執(zhí)行順序的一個(gè)迷思。這時(shí)候你該知道為什么輸出結(jié)果會(huì)是那樣,以及對(duì)裝飾器執(zhí)行順序?qū)嶋H發(fā)生了什么有一定了解了吧。 探究多個(gè)裝飾器執(zhí)行順序 裝飾器是Python用于封裝函數(shù)或代碼的工具,網(wǎng)上可以搜到很多文章可以學(xué)習(xí),我在這里要討論的是多個(gè)裝飾器執(zhí)行順序的一個(gè)迷思。 疑問 大部...

    frolc 評(píng)論0 收藏0
  • python 裝飾器 part2

    摘要:裝飾器傳參被裝飾的函數(shù)帶有參數(shù)的情況接上一篇,直接上代碼函數(shù)也就是被裝飾的函數(shù)的運(yùn)行時(shí)間是裝飾器的正確使用,不需要傳參裝飾器的正確使用,需要傳參此時(shí)不用再像上面一樣賦值,可以直接調(diào)用返回值被裝飾的函數(shù)有返回值在裝飾器內(nèi)部需被裝飾函數(shù)的調(diào)用 python 裝飾器 傳參 被裝飾的函數(shù)帶有參數(shù)的情況 接上一篇,直接上代碼 import time def decorator(func): ...

    sanyang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<