成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Python中裝飾器的示例分析-創(chuàng)新互聯(lián)

這篇文章主要為大家展示了“Python中裝飾器的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Python中裝飾器的示例分析”這篇文章吧。

網(wǎng)站設(shè)計(jì)制作過程拒絕使用模板建站;使用PHP+MYSQL原生開發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺管理系統(tǒng);網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營了10年的創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司。

需要理解的一些概念

要理解Python中的裝飾器,我覺得還是應(yīng)該從最基本的概念開始:

裝飾器模式:所謂的裝飾器模式,可以簡單地理解為“在不改變原有內(nèi)部實(shí)現(xiàn)的情況下,為函數(shù)或者類添加某種特性”。這樣我們就可以將一些與業(yè)務(wù)無關(guān)、具有通用性的代碼抽象出來,作為裝飾器附加到需要這些代碼的函數(shù)或者類之上。用面向切面編程的思想解釋就是“裝飾器應(yīng)該是一個切面”。

函數(shù)是一等公民:意思就是函數(shù)可以被當(dāng)成普通變量一樣使用。在Python中,可以把函數(shù)賦值給變量,可以將函數(shù)作為其它函數(shù)的參數(shù),也可以將函數(shù)作為其它函數(shù)的返回值。

閉包:我們都知道局部作用域可以引用全局作用域中的變量,相似的,當(dāng)一個函數(shù)內(nèi)部又定義了其它函數(shù)的時候,內(nèi)部函數(shù)可以使用外部函數(shù)所在作用域的變量,這就是閉包。

從最簡單的裝飾器做起

理解完以上的概念之后,我們嘗試一下利用這些特性實(shí)現(xiàn)一個簡單的裝飾器。

首先明確一下需求,我們有時候會需要在函數(shù)調(diào)用時打印一個相應(yīng)的日志,雖然可以通過在所有需要打印日志的函數(shù)代碼中嵌入打印日志的代碼來實(shí)現(xiàn),但這種方法不僅增加了許多重復(fù)代碼,而且在業(yè)務(wù)代碼中嵌入與業(yè)務(wù)無關(guān)的代碼增加了整體的耦合度。因此,我們需要實(shí)現(xiàn)一個裝飾器,這個裝飾器在函數(shù)調(diào)用時可以打印一個日志記錄函數(shù)調(diào)用行為。

如果我們有以下函數(shù)foo,代表具體的業(yè)務(wù)函數(shù):

def foo():
  print('in function foo')

我們設(shè)想通過調(diào)用foo = deco(foo)實(shí)現(xiàn)給函數(shù)foo增加打印日志的功能,并且不影響它原有的業(yè)務(wù)。那么在這種設(shè)想下,裝飾器deco應(yīng)該也是一個函數(shù),它接收另一個函數(shù)作為輸入,并返回一個新的、經(jīng)過裝飾的函數(shù)。在Python中,我們可以這么寫:

def deco(func): # 接收一個函數(shù)作為參數(shù)
  def new_func():
    print(f'[log] run function {func.__name__}') # 此處使用了Python3.6的格式化字符串
    func() # 閉包,在內(nèi)部函數(shù)中使用了外部函數(shù)的變量
  return new_func # 將新函數(shù)作為返回值返回

執(zhí)行一下試試效果:

>>> foo = deco(foo)
>>> foo()
[log] run function foo
in function foo

不錯,至此我們已經(jīng)實(shí)現(xiàn)了一個最簡單的裝飾器!在上面的代碼中,裝飾器deco接收任意的函數(shù)作為參數(shù),再在內(nèi)部構(gòu)造另一個函數(shù),利用閉包的特性,可以在新函數(shù)里調(diào)用存在于裝飾器deco局部作用域中的函數(shù)func。

神奇的@

按照上面那么寫,每次我們都得為需要裝飾的函數(shù)賦一個新值,萬一函數(shù)或者裝飾器的數(shù)量增加了,手動寫賦值和函數(shù)調(diào)用就會變得非常麻煩。那么在Python中,有沒有更優(yōu)雅的寫法呢?答案是有的,你只需要一個@符號。

在Python中,當(dāng)我們需要一個裝飾器時:

def deco(func):
  def new_func():
    print(f'[log] run function {func.__name__}')
    func()
  return new_func

@deco
def foo():
  print('in function foo')

這個地方我們省略了函數(shù)的賦值,直接在函數(shù)foo定義的上一行加上@deco進(jìn)行裝飾。運(yùn)行一下試試看:

>>> foo()
[log] run function foo
in function foo

是不是感覺很神奇?其實(shí)這里面沒什么魔法,只不過是Python在處理函數(shù)定義的代碼時,幫你在其中把foo=deco(foo)的邏輯加上了而已。

裝飾器也想要參數(shù)

上面的代碼實(shí)現(xiàn)了在業(yè)務(wù)函數(shù)調(diào)用之前打印日志的功能,那如果我們需要在業(yè)務(wù)代碼執(zhí)行完之后打印一條自定義的消息,怎么辦呢?我們必須要讓我們的裝飾器可以接收自定義參數(shù)。

上面提到過,Python做的只是當(dāng)寫了@deco時,把調(diào)用deco(func)的結(jié)果賦值給它裝飾的函數(shù)而已。順著這個邏輯,當(dāng)我們需要一個帶參數(shù)的裝飾器時,代碼上應(yīng)該是寫為@deco('some message'),這時Python將調(diào)用deco(msg)(func)的結(jié)果賦值給foo。那么事情就變得簡單了,我們只需要在上面代碼的基礎(chǔ)上嵌套一層函數(shù):

def deco(msg):
  def inner_deco(func):
    def new_func():
      print(f'[log] run function {func.__name__}')
      func()
      print(f'[log] {msg}')
    return new_func
  return inner_deco

@deco('some message')
def foo():
  print('in function foo')

執(zhí)行一下試試:

>>> foo()
[log] run function foo
in function foo
[log] some message

不支持帶參數(shù)的被裝飾函數(shù)的裝飾器不是好裝飾器

上面的代碼還是有問題,因?yàn)槲覀冎豢紤]了函數(shù)foo沒有參數(shù)時的情況,萬一函數(shù)foo帶了參數(shù),這個裝飾器就會丟失參數(shù)信息,這不是一個合格的裝飾器應(yīng)該出現(xiàn)的情況。所以,我們借助Python中的*args和**kwargs使被裝飾的函數(shù)可以支持傳入任意參數(shù):

def deco(msg):
  def inner_deco(func):
    def new_func(*args, **kwargs):
      print(f'[log] run function {func.__name__}')
      func(*args, **kwargs)
      print(f'[log] {msg}')
    return new_func
  return inner_deco

@deco('some message')
def foo(a, b=None):
  print('in function foo')
  print(f'a is {a} & b is ')

這樣一來,無論函數(shù)foo的參數(shù)列表是怎么樣的都不會有問題了:

>>> foo('hello')
[log] run function foo
in function foo
a is hello & b is None
[log] some message

不支持有返回值的被裝飾函數(shù)的裝飾器不是好裝飾器

別忘了,到目前為止,我們寫的函數(shù)foo都沒有返回值,如果函數(shù)foo有返回值怎么辦呢?我想你心里應(yīng)該有答案了:

def deco(msg):
  def inner_deco(func):
    def new_func(*args, **kwargs):
      print(f'[log] run function {func.__name__}')
      rlt = func(*args, **kwargs)
      print(f'[log] {msg}')
      return rlt
    return new_func
  return inner_deco

@deco('some message')
def foo(a, b=None):
  print('in function foo')
  print(f'a is {a} & b is ')
  return 'ok'

由于裝飾器在原函數(shù)執(zhí)行完之后還有別的操作,所以應(yīng)該把返回值暫存起來,等到裝飾器的邏輯執(zhí)行完畢,才返回最終結(jié)果。這就是我們的最終版裝飾器了!

>>> rlt = foo('a')
[log] run function foo
in function foo
a is a & b is None
[log] some message
>>> print(rlt)
ok

有沒有更騷的操作?

當(dāng)然有啊!我標(biāo)題都這么寫了難不成會沒有?

在Python中,你可以使用類來作為裝飾器:

class Deco(object):
  def __call__(self, func):
    def new_func():
      print(f'[log] run function {func.__name__}')
      func()
    return new_func

@Deco()
def foo():
  print('in function foo')
>>> foo()
[log] run function foo
in function foo

這么做的好處就是可以利用類更好地管理參數(shù)和調(diào)用邏輯,比起之前三層函數(shù)嵌套的形式是不是清晰多了?

在Python中,你還可以使用裝飾器來裝飾一個類,比如這樣:

def add_doc(doc):
  def deco(cls):
    cls.__doc__ = doc
    return cls
  return deco

@add_doc('this is the doc of Cls')
class Cls(object):
  pass

來看看效果:

>>> help(Cls)
Help on class Cls in module __main__:

class Cls(builtins.object)
 | this is the doc of Cls

上面的代碼只是一個示例,展示裝飾器怎么裝飾一個類而已,不是說在實(shí)際情況下應(yīng)該這么用。大部分的情況下,我們對于類的拓展應(yīng)該是通過繼承而不是裝飾。

具體怎么巧妙地利用裝飾器就要靠大家發(fā)揮自己的想象力了。

以上是“Python中裝飾器的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

名稱欄目:Python中裝飾器的示例分析-創(chuàng)新互聯(lián)
當(dāng)前URL:http://jinyejixie.com/article10/djsggo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊全網(wǎng)營銷推廣、品牌網(wǎng)站設(shè)計(jì)、關(guān)鍵詞優(yōu)化、網(wǎng)站營銷網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

營銷型網(wǎng)站建設(shè)
繁峙县| 电白县| 资中县| 垣曲县| 陆川县| 论坛| 木兰县| 海盐县| 安溪县| 东辽县| 平遥县| 宕昌县| 梁平县| 莲花县| 黄浦区| 静海县| 田林县| 沁源县| 开远市| 博客| 耒阳市| 营口市| 宁乡县| 汶川县| 外汇| 牡丹江市| 石泉县| 三江| 临城县| 侯马市| 鹿泉市| 敦煌市| 竹北市| 宁陕县| 广南县| 揭西县| 定远县| 北辰区| 无棣县| 凉城县| 陆川县|