1. 程式人生 > >Python裝飾器探究——裝飾器引數

Python裝飾器探究——裝飾器引數

通常我們見到的簡單裝飾器這樣的:

1234567891011121314 import jsonimport functoolsdef json_output(func):@functools.wraps(decorated)def inner(*args,**kwargs):result=func(*args,**kwargs)returnjson.dumps(result)returninner@json_outputdeff():return{'status':'done'}

當裝飾器應用於函式 f

上時,它接受 f 作為其引數,返回一個函式 inner ,且將他繫結到變數f上。

示例中我們編寫的裝飾器 json_output 只接受一個隱式引數——即被裝飾的方法,在使用此裝飾器時本身看上去是並沒有引數的。然而有時候需要讓裝飾器自身帶有一些需要的資訊,從而使裝飾器可以使用恰當的方式裝飾方法。比如上面的例子中,我們想通過向裝飾器傳入不同的引數來控制輸出結果的縮排(indent)和排序(sort)。我們可以這麼做:

12345678910111213141516 import jsonimport functoolsdef json_output(indent=None,sort_keys=False):def actual_decorator(func):@functools.wraps(func)def inner(*args,**kwargs):result=func(*args,**kwargs)returnjson.dumps(result,indent=indent,sort_keys=sort_keys)returninnerreturnactual_decorator@json_output(indent=4)deff():return{'status':'done'}

理解傳參的裝飾器

初次看起來會覺得比較繞人,因為函式裡嵌套了兩個函式定義,然而實際上和之前一個版本的區別在於為了接收json序列化的引數多包裝了一層,所以

123456789 @json_output(indent=4)deff():return{'status':'done'}# 相當於@actual_decoratordeff():return{'status':'done'}

這樣看起來就會明晰很多。

實際上, 裝飾器裡的 @ 後接收一個函式,該函式以被裝飾的函式(例子中是f)為引數,並且返回一個函式。當需要在裝飾函式的同時傳入引數的話,那麼就需要多包裝一層,先傳入引數(例子中是 indent=4 )返回一個裝飾的函式(例子中是 actual_decorator ), 這個返回的的函式 就跟以前一樣接受被裝飾的函式(f)作為引數並且返回一個函式作為裝飾最後的方法供呼叫。

傳參和不傳參的相容

然而當我們像上面那樣定義裝飾器時,就不能這樣呼叫:

12345678910111213141516 import jsonimport functoolsdef json_output(indent=None,sort_keys=False):def actual_decorator(func):@functools.wraps(func)def inner(*args,**kwargs):result=func(*args,**kwargs)returnjson.dumps(result,indent=indent,sort_keys=sort_keys)returninnerreturnactual_decorator@json_outputdeff():return{'status':'done'}

在實際的專案過程中,有時會出現這樣的狀況: 一開始寫的裝飾器時不需要使用時傳引數的,後來發現有必要傳引數,改好後原來不傳參的裝飾器不能正常使用了,這是修改原來使用的地方是項痛苦的事情。
這時候就需要對裝飾器做一個相容,使它在以下情況都可用:

1234 @json_output@json_output()@json_output(indent=4)

具體做法如下:

1234567891011121314151617181920212223242526272829303132333435 import jsonimport functoolsdef json_output(decorated_=None,indent=None,sort_keys=False):ifdecorated_ and(indent orsort_keys):raisedef actual_decorator(func):@functools.wraps(func)def inner(*args,**kwargs):result=func(*args,**kwargs)returnjson.dumps(result,indent=indent,sort_keys=sort_keys)returninnerifdecorated_:returnactual_decorator(decorated_)else:returnactual_decorator@json_output(indent=4)def f1():return{'status':'done'}@json_outputdef f2():return{'status':'done'}@json_output()def f3():return{'status':'done'}print f1()print f2()print f3()

程式碼中關鍵的地方在於 json_output 在最後對引數 decorated 進行了判斷,有的話證明是不傳參呼叫,那麼直接返回 actual_decorator 的呼叫;沒有的話則代表是傳參型別的呼叫(雖然引數可能不存在),那麼返回 actual_decorator 。其中有點需要注意, josn_output 的傳參需要使用關鍵字引數,如果像下面這樣直接傳一個位置引數,那麼根據現在的實現會出現錯誤(因為它會被當成 decorated_ )。

1234 @json_output(4)#錯誤的使用方法def f4():return{'status':'done'}

參考資料

  • 《Python高階程式設計》 by Luke Sneeriger

相關推薦

Python裝飾探究——裝飾引數

通常我們見到的簡單裝飾器這樣的: import json import functools def json_output(func): @functools.wraps(decorated) def inner(*args, *

python】詳解裝飾@的使用:效能測試、裝飾引數、呼叫順序、內建裝飾

python中使用’@’ 作為函式的修飾符,可以在模組或者類的定義層內對函式進行修飾,出現在函式定義的前一行,不允許和函式定義在同一行。一個修飾符就是一個函式,它將被修飾的函式作為引數,並返回修飾後的同名函式或其他可呼叫的東西。 裝飾模式有很多經典的使用場景,例如插入日誌、效能測試、事務處理等等,有了裝飾器

python裝飾:有引數裝飾、不定長引數裝飾裝飾有返回值的函式、通用的裝飾

將一個函式作為另一個函式的引數,返回值賦給這個函式 def func(funcname): print("----fun 1---") def fun_in(): print("----fun_in----1") funcname() print("----

python 類內部裝飾的實現 與 引數解構學習

學習了函式的裝飾器的寫法,然後想到如果要在類中初始化或獲取資訊時能用裝飾器做過濾和驗證應該怎麼寫呢, 在網上查了下相關資訊,感覺這樣也是可以的,不知道會不會有什麼問題class Ctj(): class Ctj(): sex = 'man' name = 'name' age

Python-裝飾以及對帶有引數裝飾的理解

請編寫一個decorator,能在函式呼叫的前後打印出’begin call’和’end call’的日誌。 再思考一下能否寫出一個@log的decorator,使它既支援: @log def f(): pass 又支援: @log('e

python 9-3 如何定義帶引數裝飾,提取函式簽名python3 inspect.signature()

9-3 如何定義帶引數的裝飾器 提取函式簽名python3 inspect.signature() 帶引數的裝飾器,也就是根據引數定製化一個裝飾器可以看生成器的工廠 每次呼叫typeassert,

python函數下篇裝飾和閉包,外加作用域

發揮 作用域 fat 功能 user div 日誌 code 返回函數 裝飾器和閉包的基礎概念 裝飾器是一種設計模式能實現代碼重用,經常用於查日誌,性能測試,事務處理等,抽離函數大量不必的功能。 裝飾器:1、裝飾器本身是一個函數,用於裝飾其它函數:2、功能:增強被裝飾函數的

Python單元測試--使用裝飾實現測試跳過和預期故障

mar 標記 失敗 assertion 可能 -s dev https one Python單元測試unittest中提供了一下四種裝飾器實現測試跳過和預期故障。(使用Python 2.7.13) 請查考Python手冊中: https://docs.python.org

python閉包和裝飾(轉)

lee type ade 機制 並且 change -1 pri neu 一、python閉包 1、內嵌函數 >>> def func1(): ... print (‘func1 running...‘) ... def func2(

Python自學之樂-裝飾淺談

擴展性 func 可擴展性 函數調用 順序 簡單的 代碼 tar 統計 以前學過點 面向對象的知識,我感覺這之間是有關聯的,比如說裝飾器的第一個要素是對被裝飾的函數的封閉性,不允許更改;第二個就是對裝飾器本oj身的可擴展性。 裝飾器要點:高階函數+嵌套函數=裝飾器 需要掌握

Python學習之路-裝飾&生成器&正則表達式

python 生成器 裝飾器 正則表達式 裝飾器通俗的講,裝飾器就是在不改變源代碼基礎上,給源代碼增加新功能。不改變函數的源代碼、調用方式、返回值等,給函數增加新功能。經典案例:登錄裝飾器,def login_decorator(func): def inner():

Python--閉包與裝飾

python 閉包 裝飾器 閉包的意義:返回的函數對象,不僅僅是一個函數對象,在該函數外還包裹了一層作用域,這使得,該函數無論在何處調用,優先使用自己外層包裹的作用域 #應用領域:延遲計算(原來我們是傳參,現在我們是包起來)from urllib.request import urlopen

python魔術方法之裝飾

裝飾器 描述器 三個魔術方法:__get__()__set__()__delete__()object.__get__(self,實例名,owner) #owner = 屬主 ,instance = 屬主類owner的實例object.__set__(self,實例名,value)object.

python學習第四天,列表生產式,匿名函數,生成器,內置函數,叠代裝飾,json和pickle的序列化和反序列化

數據 其他 imp 函數名 fun pro serializa and cal 列表生成式,生產器 #列表生成式,可以是代碼更復雜 a = [i for i in range(10)] #這裏的i,可以使用函數來裝飾 print(a) #生產器:就是數據在調用的時候才有

python 入坑路--裝飾(語法糖)--高高潮

wrapper else clas inpu 參數 index word com oca 上回我們說到,傳入的函數帶參數,這回我們要說的是,裝飾器帶參數,那麽裝飾器要如何是好。 1 u_n="keven" 2 passwd="abc123" 3 4 def au

Learn Python—函數(裝飾

結果 註釋 return rom 添加 body urn 簡單 裝飾器 裝飾器 開放封閉原則 開放:對函數的擴展是開放的 封閉:對函數的修改是封閉的 裝飾器的作用 在不更改原函數調用方式的前提下,對原函數添加新功能 # ①引子——為什麽要有裝飾器 為了在不修改原函數的基礎

python學習筆記(五):裝飾、生成器、內置函數、json

知識 我們 數列 ext 返回 utf choice 斐波拉契數列 不同 一、裝飾器 裝飾器,這個器就是函數的意思,連起來,就是裝飾函數,裝飾器本身也是一個函數,它的作用是用來給其他函數添加新功能,比如說,我以前寫了很多代碼,系統已經上線了,但是性能比較不好,現在想把程序裏

Python函數(八)-裝飾(一)

裝飾器 lee author brush light log 裝飾 true 源代碼 裝飾器通過函數來定義,用來裝飾函數 裝飾器不改變被裝飾函數的源代碼和運行方式 如何實現這個效果呢? # -*- coding:utf-8 -*- __author__ = "MuT6 S

Python函數(十)-裝飾(三)

進行 src def int 技術 put 功能 bubuko div 如果多個函數想通過一個裝飾器來實現不同的功能的話,可以給裝飾器傳入參數,讓裝飾器裏的函數對參數進行判斷,來實現不同的功能 # -*- coding:utf-8 -*- __author__ = "Mu

Python之旅:裝飾

解決 裝飾器 開放 擴展 nbsp 場景 應用場景 閉包 軟件 裝飾器就是閉包函數的一種應用場景 一、為何要用裝飾器 開放封閉原則:軟件一旦上線後,就應該遵循開放封閉原則,即對修改源代碼是封閉的,對功能的擴展是開放的       也就是說我們必須找到一種解決方