2.閉包和裝飾器

閉包:https://zhuanlan.zhihu.com/p/93846887
裝飾器:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017451662295584
https://www.cnblogs.com/yaoqingzhuan/p/10628592.html
python參考手冊(cè):相關(guān)章節(jié)

一.預(yù)備知識(shí)

1.作用域、內(nèi)嵌函數(shù)、生命周期

python中的每個(gè)函數(shù)都是一個(gè)新的作用域,或者理解為命名空間
一般而言,函數(shù)中定義的變量、內(nèi)嵌函數(shù)等,其生命周期即所在函數(shù)的作用域,當(dāng)函數(shù)執(zhí)行完畢后,函數(shù)內(nèi)所定義變量、內(nèi)嵌函數(shù)等都應(yīng)該會(huì)消失。而在下一次調(diào)用時(shí),又會(huì)被重新創(chuàng)建。

2.變量搜索

當(dāng)在函數(shù)中訪問(wèn)一個(gè)新的變量時(shí),python會(huì)在當(dāng)前命名空間中尋找該變量是否存在。如果不存在則會(huì)從上一級(jí)命名空間中搜尋,直到頂層命名空間。比如:


image.png

但是在函數(shù)中對(duì)一個(gè)變量進(jìn)行定義或者賦值時(shí),python只會(huì)在當(dāng)前命名空間中搜尋該變量,如果不存在,則會(huì)創(chuàng)建一個(gè)新的變量。如果上一級(jí)命名空間中存在同名的變量,那么上一級(jí)同名變量會(huì)在當(dāng)前作用于中被覆蓋。


image.png

二.閉包

1.定義
將組成函數(shù)的語(yǔ)句和這些語(yǔ)句執(zhí)行環(huán)境打包在一起時(shí),得到的對(duì)象稱為閉包。

2.使用場(chǎng)景
函數(shù)在python中是第一類對(duì)象。也就是說(shuō)可以把他們當(dāng)作參數(shù)傳遞給其他函數(shù)、放在數(shù)據(jù)結(jié)構(gòu)中、以及作為函數(shù)的返回結(jié)果等。(這些場(chǎng)景都會(huì)觸發(fā)閉包)
把函數(shù)當(dāng)作數(shù)據(jù)處理時(shí),它將隱式地?cái)y帶與定義該函數(shù)的周圍環(huán)境相關(guān)的信息(該函數(shù)所需的所有信息)。

3.舉例說(shuō)明

  • 示例1:閉包影響自由變量的綁定方式
# foo.py
x = 42
def callf(func):
  return func()

# 調(diào)用代碼
import foo
x = 37
def helloworld():
  return "Hello world, x is %d" %x
fool.callf(helloworld)

輸出結(jié)果:
Hello world, x is 37
  • 示例2:閉包捕捉函數(shù)執(zhí)行所需的整個(gè)環(huán)境


    image.png

    從作用域的角度:foo實(shí)際上是調(diào)用了內(nèi)嵌函數(shù)inner(), 當(dāng)執(zhí)行到inner中的print(x)語(yǔ)句時(shí),在inner()中沒(méi)有搜尋到x,然后會(huì)在outer()命名空間中搜尋,找到x后進(jìn)行打印。
    從生命周期的角度,foo的值為outer函數(shù)的返回值,當(dāng)執(zhí)行foo()時(shí),outer函數(shù)已經(jīng)執(zhí)行完畢了,此時(shí)其作用于內(nèi)定義的變量x也應(yīng)該已經(jīng)銷毀,因此執(zhí)行foo()時(shí),當(dāng)執(zhí)行到print(x)時(shí),應(yīng)該會(huì)出錯(cuò)。但實(shí)際上并沒(méi)有。
    這其實(shí)是python支持函數(shù)閉包的特性。

三.裝飾器

閉包會(huì)捕捉內(nèi)部的環(huán)境信息,因此還可以用于包裝現(xiàn)有函數(shù)。

1.定義

裝飾器是一個(gè)函數(shù)(也可以是類或者對(duì)象),其主要用途是包裝另一個(gè)函數(shù)或者。這種包裝的首要目的是光明睜大的修改或者增強(qiáng)被包裝對(duì)象的行為。

2.分類

1.函數(shù)裝飾器

根據(jù)裝飾器本身是否接受參數(shù),可以分為:帶參數(shù)的裝飾器和不帶參數(shù)的裝飾器
A.不帶參數(shù)的裝飾器:包裝的函數(shù)func本身,作為裝飾器的入?yún)ⅰ?/p>

@trace
def square(x):
  return x*x

#其等價(jià)于:
def square(x):
  return x*x
square = trace(square)

# trace代碼的實(shí)現(xiàn)如下
# 備注:內(nèi)部函數(shù)callf作為返回值,是一個(gè)閉包
def trace(func):
  def callf(*args, **kwargs):
    debug_log.write('calling args:%s' % args)
    r = func(*args, **kwargs)
    debug_log.write('%s returned' % r)
    return r
  return callf

B.帶參數(shù)的裝飾器(多一層對(duì)裝飾器參數(shù)的處理)
首先:參數(shù)param作為裝飾器的入?yún)?,返回第一層函?shù):W。(第一層:對(duì)裝飾器本身參數(shù)的處理)
然后:將包裝的函數(shù)func本身,作為W的入?yún)?,傳遞執(zhí)行。(第二層:對(duì)包裝函數(shù)的處理,不帶參數(shù)的裝飾器,只有該層)

# 裝飾器帶參數(shù)的版本:
def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

# 其含義是:
now = log('execute')(now)

# 裝飾器本身不帶參數(shù)的版本:
def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
# 其含義是:
now = log(now)
2.使用類作為裝飾器

類也可以作為裝飾器。


image.png
3.使用對(duì)象作為裝飾器

根據(jù)裝飾器的語(yǔ)法,對(duì)象也可以作為裝飾器。使用對(duì)象裝飾器有時(shí)候會(huì)更加靈活,例如能夠方便的定制和添加參數(shù)。


image.png
4.裝飾器裝飾類

接受類作為輸入,并返回類作為輸出


image.png

備注:
由此可見(jiàn),@本身是一個(gè)python的語(yǔ)法糖。它只是按照固定格式進(jìn)行展開(kāi),展開(kāi)后只要符合python語(yǔ)法,不論是:類、對(duì)象、函數(shù)等,都允許靈活的搭配使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在學(xué)習(xí) Python 的時(shí)候,慶幸自己有 JavaScript 的基礎(chǔ),在學(xué)習(xí)過(guò)程中,發(fā)現(xiàn)許多相似的地方,如導(dǎo)包的...
    柏丘君閱讀 1,275評(píng)論 2 8
  • 導(dǎo)讀:Python中的裝飾器經(jīng)常用于有切面需求的場(chǎng)景,較為經(jīng)典的有插入日志、性能測(cè)試、事務(wù)處理等。本文從閉包的概念...
    zgjx閱讀 469評(píng)論 0 3
  • 一直不理解裝飾器原理,在知乎上找到一篇詳細(xì)的講解文章,原文貼了上來(lái)。知乎裝飾器原文鏈接 1. Python中一切皆...
    Pig_deng飼養(yǎng)員閱讀 285評(píng)論 0 0
  • 前言 裝飾器作為Python語(yǔ)言很重要的一個(gè)特性,在實(shí)際開(kāi)發(fā)中,我們都經(jīng)常用到,包括面試的時(shí)候也會(huì)拿出來(lái)問(wèn),所以想...
    BourneKing閱讀 248評(píng)論 0 0
  • 閉包的定義 將組成函數(shù)的語(yǔ)句和這些語(yǔ)句的執(zhí)行環(huán)境打包在一起時(shí),得到的對(duì)象稱為閉包我們知道函數(shù)在Python中是第一...
    So_ProbuING閱讀 297評(píng)論 0 0

友情鏈接更多精彩內(nèi)容