欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python函數(shù)編程——閉包和裝飾器

系統(tǒng) 1665 0

Python函數(shù)編程——閉包和裝飾器

一、閉包

關(guān)于閉包,即函數(shù)定義和函數(shù)表達(dá)式位于另一個(gè)函數(shù)的函數(shù)體內(nèi)(嵌套函數(shù))。而且,這些內(nèi)部函數(shù)可以訪問(wèn)它們所在的外部函數(shù)中聲明的所有局部變量、參數(shù)。當(dāng)其中一個(gè)這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時(shí),就會(huì)形成閉包。也就是說(shuō),內(nèi)部函數(shù)會(huì)在外部函數(shù)返回后被執(zhí)行。而當(dāng)這個(gè)內(nèi)部函數(shù)執(zhí)行時(shí),它仍然必需訪問(wèn)其外部函數(shù)的局部變量、參數(shù)以及其他內(nèi)部函數(shù)。這些局部變量、參數(shù)和函數(shù)聲明(最初時(shí))的值是外部函數(shù)返回時(shí)的值,但也會(huì)受到內(nèi)部函數(shù)的影響。

          
            def outer():
    name = 'alex'
    def inner():
        print("在inner里打印外層函數(shù)的變量",name)
    return inner # 注意這里只是返回inner的內(nèi)存地址,并未執(zhí)行
f = outer() # .inner at 0x1027621e0> 
f()  # 相當(dāng)于執(zhí)行的是inner()
          
        

注意此時(shí)outer已經(jīng)執(zhí)行完畢,正常情況下outer里的內(nèi)存都已經(jīng)釋放了,但此時(shí)由于閉包的存在,我們卻還可以調(diào)用inner, 并且inner內(nèi)部還調(diào)用了上一層outer里的name變量。這種粘粘糊糊的現(xiàn)象就是閉包。

閉包的意義: 返回的函數(shù)對(duì)象,不僅僅是一個(gè)函數(shù)對(duì)象,在該函數(shù)外還包裹了一層作用域,這使得,該函數(shù)無(wú)論在何處調(diào)用,優(yōu)先使用自己外層包裹的作用域。

閉包在哪會(huì)用? 請(qǐng)往下看。

二、裝飾器

請(qǐng)看完下面這個(gè)故事!!!!

你是一家視頻網(wǎng)站的后端開(kāi)發(fā)工程師,你們網(wǎng)站有以下幾個(gè)版塊。

          
            def home():
    print("---首頁(yè)----")
def america():
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
def henan():
    print("----河南專區(qū)----")
          
        

視頻剛上線初期,為了吸引用戶,你們采取了免費(fèi)政策,所有視頻免費(fèi)觀看,迅速吸引了一大批用戶,免費(fèi)一段時(shí)間后,每天巨大的帶寬費(fèi)用公司承受不了了,所以準(zhǔn)備對(duì)比較受歡迎的幾個(gè)版塊收費(fèi),其中包括“歐美” 和 “河南”專區(qū),你拿到這個(gè)需求后,想了想,想收費(fèi)得先讓其進(jìn)行用戶認(rèn)證,認(rèn)證通過(guò)后,再判定這個(gè)用戶是否是VIP付費(fèi)會(huì)員就可以了,是VIP就讓看,不是VIP就不讓看就行了唄。 你覺(jué)得這個(gè)需求很是簡(jiǎn)單,因?yàn)橐獙?duì)多個(gè)版塊進(jìn)行認(rèn)證,那應(yīng)該把認(rèn)證功能提取出來(lái)單獨(dú)寫(xiě)個(gè)模塊,然后每個(gè)版塊里調(diào)用 就可以了,與是你輕輕的就實(shí)現(xiàn)了下面的功能 。

          
            account = {
    "is_authenticated":False,# 用戶登錄了就把這個(gè)改成True
    "username":"alex", # 假裝這是DB里存的用戶信息
    "password":"abc123" # 假裝這是DB里存的用戶信息
}
def login():
    if account["is_authenticated"] is False:
        username = input("user:")
        password = input("pasword:")
        if username == account["username"] and password == account["password"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password!")
    else:
        print("用戶已登錄,驗(yàn)證通過(guò)...")
def home():
    print("---首頁(yè)----")
def america():
    login()  # 執(zhí)行前加上驗(yàn)證
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
def henan():
    login()  # 執(zhí)行前加上驗(yàn)證
    print("----河南專區(qū)----")
home()
america()
henan()
          
        

此時(shí)你信心滿滿的把這個(gè)代碼提交給你的TEAM LEADER審核,沒(méi)成想,沒(méi)過(guò)5分鐘,代碼就被打回來(lái)了, TEAM LEADER給你反饋是,我現(xiàn)在有很多模塊需要加認(rèn)證模塊,你的代碼雖然實(shí)現(xiàn)了功能,但是需要更改要加認(rèn)證的各個(gè)模塊的源代碼,這直接違反了軟件開(kāi)發(fā)中的一個(gè)原則“開(kāi)放-封閉”原則,簡(jiǎn)單來(lái)說(shuō),它規(guī)定已經(jīng)實(shí)現(xiàn)的功能代碼不應(yīng)該被修改,但可以被擴(kuò)展,即:

  • 封閉:已實(shí)現(xiàn)的功能代碼塊不應(yīng)該被修改
  • 開(kāi)放:對(duì)現(xiàn)有功能的擴(kuò)展開(kāi)放

這個(gè)原則你還是第一次聽(tīng)說(shuō),我擦,再次感受了自己這個(gè)野生程序員與正規(guī)軍的差距,BUT ANYWAY,老大要求的這個(gè)怎么實(shí)現(xiàn)呢?如何在不改原有功能代碼的情況下加上認(rèn)證功能呢?你一時(shí)想不出思路,只好帶著這個(gè)問(wèn)題回家繼續(xù)憋,媳婦不在家,去隔壁老王家串門(mén)了,你正好落的清靜,一不小心就想到了解決方案,不改源代碼可以呀。 你師從沙河金角大王時(shí),記得他教過(guò)你,高階函數(shù),就是把一個(gè)函數(shù)當(dāng)做一個(gè)參數(shù)傳給另外一個(gè)函數(shù),當(dāng)時(shí)大王說(shuō),有一天,你會(huì)用到它的,沒(méi)想到這時(shí)這個(gè)知識(shí)點(diǎn)突然從腦子里蹦出來(lái)了,我只需要寫(xiě)個(gè)認(rèn)證方法,每次調(diào)用 需要驗(yàn)證的功能 時(shí),直接 把這個(gè)功能 的函數(shù)名當(dāng)做一個(gè)參數(shù) 傳給 我的驗(yàn)證模塊不就行了么,哈哈,機(jī)智如我,如是你啪啪啪改寫(xiě)了之前的代碼。

          
            account = {
    "is_authenticated":False,# 用戶登錄了就把這個(gè)改成True
    "username":"alex", # 假裝這是DB里存的用戶信息
    "password":"abc123" # 假裝這是DB里存的用戶信息
}
def login(func):
    if account["is_authenticated"] is False:
        username = input("user:")
        password = input("pasword:")
        if username == account["username"] and password == account["password"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password!")
    if account["is_authenticated"] is True:  # 主要改了這
        func() # 認(rèn)證成功了就執(zhí)行傳入進(jìn)來(lái)的函數(shù)
def home():
    print("---首頁(yè)----")
def america():
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
def henan():
    print("----河南專區(qū)----")
home()
login(america) # 需要驗(yàn)證就調(diào)用 login,把需要驗(yàn)證的功能 當(dāng)做一個(gè)參數(shù)傳給login
login(henan)
          
        

你很開(kāi)心,終于實(shí)現(xiàn)了老板的要求,不改變?cè)δ艽a的前提下,給功能加上了驗(yàn)證,此時(shí),媳婦回來(lái)了,后面還跟著老王,你兩家關(guān)系非常好,老王經(jīng)常來(lái)串門(mén),老王也是碼農(nóng),你跟他分享了你寫(xiě)的代碼,興奮的等他看完 夸獎(jiǎng)你NB,沒(méi)成想,老王看后,并沒(méi)有夸你,抱起你的兒子,笑笑說(shuō),你這個(gè)代碼還是改改吧, 要不然會(huì)被開(kāi)除的,WHAT? 會(huì)開(kāi)除,明明實(shí)現(xiàn)了功能 呀, 老王講,沒(méi)錯(cuò),功能是實(shí)現(xiàn)了,但是你又犯了一個(gè)大忌,什么大忌? 你改變了調(diào)用方式呀, 想一想,現(xiàn)在沒(méi)每個(gè)需要認(rèn)證的模塊,都必須調(diào)用你的login()方法,并把自己的函數(shù)名傳給你,人家之前可不是這么調(diào)用的, 試想,如果有100個(gè)模塊需要認(rèn)證,那這100個(gè)模塊都得更改調(diào)用方式,這么多模塊肯定不止是一個(gè)人寫(xiě)的,讓每個(gè)人再去修改調(diào)用方式 才能加上認(rèn)證,你會(huì)被罵死的。。。。 你覺(jué)得老王說(shuō)的對(duì),但問(wèn)題是,如何即不改變?cè)δ艽a,又不改變?cè)姓{(diào)用方式,還能加上認(rèn)證呢? 你苦思了一會(huì),還是想不出,老王在逗你的兒子玩,你說(shuō),老王呀,快給我點(diǎn)思路 ,實(shí)在想不出來(lái),老王背對(duì)著你問(wèn),

老王:學(xué)過(guò)匿名函數(shù)沒(méi)有?

你:學(xué)過(guò)學(xué)過(guò),就是lambda嘛

老王:那lambda與正常函數(shù)的區(qū)別是什么?

你:最直接的區(qū)別是,正常函數(shù)定義時(shí)需要寫(xiě)名字,但lambda不需要

老王:沒(méi)錯(cuò),那lambda定好后,為了多次調(diào)用 ,可否也給它命個(gè)名?

你:可以呀,可以寫(xiě)成plus = lambda x:x+1類似這樣,以后再調(diào)用plus就可以了,但這樣不就失去了lambda的意義了,明明人家叫匿名函數(shù)呀,你起了名字有什么用呢?

老王:我不是要跟你討論它的意義 ,我想通過(guò)這個(gè)讓你明白一個(gè)事實(shí)

老王邊說(shuō)著,邊拿起你兒子的畫(huà)板,在上面寫(xiě)了以下代碼:

          
            def plus(n):
    return n+1
plus2 = lambda x:x+1
          
        

老王: 上面這兩種寫(xiě)法是不是代表 同樣的意思?

你:是的

老王:我給lambda x:x+1 起了個(gè)名字叫plus2,是不是相當(dāng)于def plus2(x) ?

你:我擦,你別說(shuō),還真是,但老王呀,你想說(shuō)明什么呢?

老王: 沒(méi)啥,只想告訴你,給函數(shù)賦值變量名就像def func_name 是一樣的效果,如下面的plus(n)函數(shù),你調(diào)用時(shí)可以用plus名,還可以再起個(gè)其它名字,如

          
            calc = plus
calc(n)
          
        

你明白我想傳達(dá)什么意思了么?

你:。。。。。。。。。。。這。。。。。。嗯 。。。。。不太。。。。明白 。。

老王:。。。。這。。。。。呵呵。。。。。。好吧。。。。,那我在給你點(diǎn)一下,你之前寫(xiě)的下面這段調(diào)用認(rèn)證的代碼

          
            home()
login(america) #需要驗(yàn)證就調(diào)用 login,把需要驗(yàn)證的功能 當(dāng)做一個(gè)參數(shù)傳給login
# home()
# america()
login(henan)
          
        

老王:你之所以改變了調(diào)用方式,是因?yàn)橛脩裘看握{(diào)用時(shí)需要執(zhí)行l(wèi)ogin(henan),類似的。其實(shí)稍一改就可以了呀

          
            home()
america = login(america)
henan = login(henan)
          
        

老王:這樣以后其它人調(diào)用henan時(shí),其實(shí)相當(dāng)于調(diào)用了login(henan), 通過(guò)login里的驗(yàn)證后,就會(huì)自動(dòng)調(diào)用henan功能。

你:我擦,還真是唉。。。,老王,還是你nb。。。不過(guò),等等, 我這樣寫(xiě)了好,那用戶調(diào)用時(shí),應(yīng)該是下面這個(gè)樣子

          
            home()
america = login(america) #你在這里相當(dāng)于把a(bǔ)merica這個(gè)函數(shù)替換了
henan = login(henan)
#那用戶調(diào)用時(shí)依然寫(xiě)
america()
          
        

但問(wèn)題在于,還不等用戶調(diào)用 ,你的america = login(america)就會(huì)先自己把a(bǔ)merica執(zhí)行了呀。。。。,你應(yīng)該等我用戶調(diào)用的時(shí)候再執(zhí)行才對(duì)呀,不信我試給你看。。。

老王:哈哈,你說(shuō)的沒(méi)錯(cuò),這樣搞會(huì)出現(xiàn)這個(gè)問(wèn)題,但你想想有沒(méi)有解決辦法呢?

你:我擦,你指的思路呀,大哥。。。我哪知道下一步怎么走。。。

老王:算了,估計(jì)你也想不出來(lái)。。。 學(xué)過(guò)嵌套函數(shù)沒(méi)有?

你:yes,然后呢?

老王:想實(shí)現(xiàn)一開(kāi)始你寫(xiě)的america = login(america)不觸發(fā)你真正的america函數(shù)的執(zhí)行,只需要在這個(gè)login里面再定義一層函數(shù),第一次調(diào)用america = login(america)只調(diào)用到外層login,這個(gè)login雖然會(huì)執(zhí)行,但不會(huì)觸發(fā)認(rèn)證了,因?yàn)檎J(rèn)證的所有代碼被封裝在login里層的新定義 的函數(shù)里了,login只返回 里層函數(shù)的函數(shù)名,這樣下次再執(zhí)行america()時(shí), 就會(huì)調(diào)用里層函數(shù)啦。。。

你:。。。。。。什么? 什么個(gè)意思,我蒙逼了。。。

老王:還是給你看代碼吧。。

          
            account = {
    "is_authenticated":False,# 用戶登錄了就把這個(gè)改成True
    "username":"alex", # 假裝這是DB里存的用戶信息
    "password":"abc123" # 假裝這是DB里存的用戶信息
}
def login(func):
    def inner(): # 再定義一層函數(shù)
        if account["is_authenticated"] is False:
            username = input("user:")
            password = input("pasword:")
            if username == account["username"] and password == account["password"]:
                print("welcome login....")
                account["is_authenticated"] = True
            else:
                print("wrong username or password!")
        if account["is_authenticated"] is True:
            func()
    return inner  # 注意這里只返回inner的內(nèi)存地址,不執(zhí)行
def home():
    print("---首頁(yè)----")
def america():
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
def henan():
    print("----河南專區(qū)----")
home()
america = login(america) # 這次執(zhí)行l(wèi)ogin返回的是inner的內(nèi)存地址 .inner at 0x101762840>
henan = login(henan)  # .inner at 0x102562840>
america()  # 相當(dāng)于執(zhí)行inner()
henan()
          
        

此時(shí)你仔細(xì)著了老王寫(xiě)的代碼 ,感覺(jué)老王真不是一般人呀,連這種奇淫巧技都能想出來(lái)。。。,心中默默感謝上天賜你一個(gè)大牛鄰居。

你: 老王呀,你這個(gè)姿勢(shì)很nb呀,你獨(dú)創(chuàng)的? 此時(shí)你媳婦噗嗤的笑出聲來(lái),你也不知道 她笑個(gè)球。。。

老王:呵呵, 這不是我獨(dú)創(chuàng)的呀當(dāng)然 ,這是開(kāi)發(fā)中一個(gè)常用的玩法,叫語(yǔ)法糖,官方名稱“裝飾器”,其實(shí)上面的寫(xiě)法,還可以更簡(jiǎn)單 可以把下面代碼去掉

          
            america = login(america) # 這次執(zhí)行l(wèi)ogin返回的是inner的內(nèi)存地址
henan = login(henan)  # .inner at 0x102562840>
          
        

只在你要裝飾的函數(shù)上面加上下面代碼

          
            @login
def america():
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
@login
def henan():
    print("----河南專區(qū)----")
          
        

效果是一樣的。

你開(kāi)心的玩著老王教你的新姿勢(shì) ,玩著玩著就手賤給你的“河南專區(qū)”版塊 加了個(gè)參數(shù),然后,結(jié)果出錯(cuò)了。。

Python函數(shù)編程——閉包和裝飾器_第1張圖片

你:老王,老王,怎么傳個(gè)參數(shù)就不行了呢?

老王:那必然呀,你調(diào)用henan時(shí),其實(shí)是相當(dāng)于調(diào)用的login,你的henan第一次調(diào)用時(shí)henan = login(henan), login就返回了inner的內(nèi)存地址,第2次用戶自己調(diào)用henan(5),實(shí)際上相當(dāng)于調(diào)用的是inner,但你的inner定義時(shí)并沒(méi)有設(shè)置參數(shù),但你給他傳了個(gè)參數(shù),所以自然就報(bào)錯(cuò)了呀

你:但是我的 版塊需要傳參數(shù)呀,你不讓我傳不行呀。。。

老王:沒(méi)說(shuō)不讓你傳,稍做改動(dòng)便可。。

Python函數(shù)編程——閉包和裝飾器_第2張圖片

老王:你再試試就好了 。

你: 果然好使,大神就是大神呀。 。。 不過(guò),如果有多個(gè)參數(shù)呢?

老王:。。。。老弟,你不要什么都讓我教你吧,非固定參數(shù)你沒(méi)學(xué)過(guò)么?*args,**kwargs…

你:噢 。。。還能這么搞?,nb,我再試試。 你身陷這種新玩法中無(wú)法自拔,竟沒(méi)注意到老王已經(jīng)離開(kāi),你媳婦告訴你說(shuō)為了不打擾你加班,今晚帶孩子去跟她姐妹住 ,你覺(jué)得媳婦真體貼,最終,你終于搞定了所有需求,完全遵循開(kāi)放-封閉原則,最終代碼如下。

          
            account = {
    "is_authenticated":False,# 用戶登錄了就把這個(gè)改成True
    "username":"alex", # 假裝這是DB里存的用戶信息
    "password":"abc123" # 假裝這是DB里存的用戶信息
}
def login(func):
    def inner(*args,**kwargs): # 再定義一層函數(shù)
        if account["is_authenticated"] is False:
            username = input("user:")
            password = input("pasword:")
            if username == account["username"] and password == account["password"]:
                print("welcome login....")
                account["is_authenticated"] = True
            else:
                print("wrong username or password!")
        if account["is_authenticated"] is True:
            func(*args,**kwargs)
    return inner  # 注意這里只返回inner的內(nèi)存地址,不執(zhí)行
def home():
    print("---首頁(yè)----")
@login
def america():
    print("----歐美專區(qū)----")
def japan():
    print("----日韓專區(qū)----")
@login
def henan(vip_level):
    if vip_level < 3:
        print("----河南專區(qū)普通會(huì)員----")
    else:
        print("歡迎來(lái)到尊貴河南口音RMB玩家私密社區(qū)".center(50,"-"))
        print("再充值500就可以獲取演員微信號(hào),幸福大門(mén)即將開(kāi)啟".center(50," "))
# home()
# america = login(america) # 這次執(zhí)行l(wèi)ogin返回的是inner的內(nèi)存地址 .inner at 0x101762840>
# henan = login(henan)  # .inner at 0x102562840>
america()  # 相當(dāng)于執(zhí)行inner()
henan(5)
          
        

此時(shí),你已累的不行了,洗洗就抓緊睡了,半夜,上廁所,隱隱聽(tīng)到隔壁老王家有微弱的女人的聲音傳來(lái),你會(huì)心一笑,老王這家伙,不聲不響找了女朋友也不帶給我看看,改天一定要見(jiàn)下真人。。。。。你本想著給媳婦打個(gè)電話問(wèn)問(wèn)她到了閨蜜家沒(méi)有,想著想著竟然睡著了。。。

翌日,你精神抖擻到了公司,把代碼扔給leader, leader看完后,會(huì)心一笑,小伙子不錯(cuò),這才是專業(yè)的寫(xiě)法嘛。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 日韩精品视频一区二区三区 | 久久se精品一区精品二区 | 国产chinese视频在线观看 | 99re99| 亚洲精品66| 欧美性猛交xxxx乱大交蜜桃 | 奇米四色在线观看 | 不卡一区 | 一级黄片毛片免费看 | 欧美日韩黄 | 日韩精品一区二区三区国语自制 | 欧美a级成人淫片免费看 | 高清在线不卡 | 高清中文字幕免费观在线 | 久久免费精品视频在线观看 | 欧美日韩亚洲一区二区三区在线观看 | 国产乱码精品1区2区3区 | 亚洲色图片区 | 一区二区三区视频免费 | 日本免费成人 | 亚洲国产中文字幕 | 欧美综合伊人久久 | 久久视频在线视频 | 欧美成人一级片 | 黄片一级毛片 | 国产视频在 | 欧美激情精品久久久久 | 99在线精品视频在线观看 | a视频在线看 | 国产精品久久久久久久久免费 | 国产小视频在线高清播放 | 色欲AV蜜臀AV在线观看麻豆 | 亚洲色图150p | 国产成人黄网址在线视频 | 日本欧美中文字幕人在线 | 久久久久久国产精品 | 日本黄视频在线观看 | 国产日韩精品视频 | 精品免费在线 | 男生插女生视频免费 | 免费毛片在线视频 |