python 裝飾器@wraps
預備知識
在瞭解wraps
修飾器之前,我們首先要了解partial
和update_wrapper
這兩個函式,因為在wraps
的程式碼中,用到了這兩個函式。
partial
首先說partial
函式,在官方文件的描述中,這個函式的宣告如下:functools.partial(func, *args, **keywords)
。它的作用就是返回一個partial
物件,當這個partial
物件被呼叫的時候,就像通過func(*args, **kwargs)
的形式來呼叫func
函式一樣。如果有額外的 位置引數(args) 或者 關鍵字引數(*kwargs) 被傳給了這個partial
物件,那它們也都會被傳遞給func
個人感覺這個函式很像C++中的bind
函式,都是把某個函式的某個引數固定,從而構造出一個新的函式來。比如下面這個例子:
from functools import partial
def add(x:int, y:int):
return x+y
# 這裡創造了一個新的函式add2,只接受一個整型引數,然後將這個引數統一加上2
add2 = partial(add, y=2)
add2(3) # 這裡將會輸出5
這個函式是使用C而不是Python實現的,但是官方文件中給出了Python實現的程式碼,如下所示,大家可以進行參考:
def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*args, *fargs, **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc
update_wrapper
接下來,我們再來聊一聊update_wrapper
這個函式,顧名思義,這個函式就是用來更新修飾器函式的,具體更新些什麼呢,我們可以直接把它的原始碼搬過來看一下:
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
pass
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
wrapper.__wrapped__ = wrapped
return wrapper
大家可以發現,這個函式的作用就是從 被修飾的函式(wrapped) 中取出一些屬性值來,賦值給 修飾器函式(wrapper) 。為什麼要這麼做呢,我們看下面這個例子。
自定義修飾器v1
首先我們寫個自定義的修飾器,沒有任何的功能,僅有文件字串,如下所示:
def wrapper(f):
def wrapper_function(*args, **kwargs):
"""這個是修飾函式"""
return f(*args, **kwargs)
return wrapper_function
@wrapper
def wrapped():
"""這個是被修飾的函式"""
print('wrapped')
print(wrapped.__doc__) # 輸出`這個是修飾函式`
print(wrapped.__name__) # 輸出`wrapper_function`
從上面的例子我們可以看到,我想要獲取wrapped
這個被修飾函式的文件字串,但是卻獲取成了wrapper_function
的文件字串,wrapped
函式的名字也變成了wrapper_function
函式的名字。這是因為給wrapped
新增上@wrapper
修飾器相當於執行了一句wrapped = wrapper(wrapped)
,執行完這條語句之後,wrapped
函式就變成了wrapper_function
函式。遇到這種情況該怎麼辦呢,首先我們可以手動地在wrapper
函式中更改wrapper_function
的__doc__
和__name__
屬性,但聰明的你肯定也想到了,我們可以直接用update_wrapper
函式來實現這個功能。
自定義修飾器v2
我們對上面定義的修飾器稍作修改,添加了一句update_wrapper(wrapper_function, f)
。
from functools import update_wrapper
def wrapper(f):
def wrapper_function(*args, **kwargs):
"""這個是修飾函式"""
return f(*args, **kwargs)
update_wrapper(wrapper_function, f) # << 添加了這條語句
return wrapper_function
@wrapper
def wrapped():
"""這個是被修飾的函式"""
print('wrapped')
print(wrapped.__doc__) # 輸出`這個是被修飾的函式`
print(wrapped.__name__) # 輸出`wrapped`
此時我們可以發現,__doc__
和__name__
屬性已經能夠按我們預想的那樣顯示了,除此之外,update_wrapper
函式也對__module__
和__dict__
等屬性進行了更改和更新。
wraps修飾器
OK,至此,我們已經瞭解了partial
和update_wrapper
這兩個函式的功能,接下來我們翻出wraps
修飾器的原始碼:
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
沒錯,就是這麼的簡單,只有這麼一句,我們可以看出,wraps
函式其實就是一個修飾器版的update_wrapper
函式,它的功能和update_wrapper
是一模一樣的。我們可以修改我們上面的自定義修飾器的例子,做出一個更方便閱讀的版本。
自定義修飾器v3
from functools import wraps
def wrapper(f):
@wraps(f)
def wrapper_function(*args, **kwargs):
"""這個是修飾函式"""
return f(*args, **kwargs)
return wrapper_function
@wrapper
def wrapped():
"""這個是被修飾的函式
"""
print('wrapped')
print(wrapped.__doc__) # 輸出`這個是被修飾的函式`
print(wrapped.__name__) # 輸出`wrapped`
至此,我想大家應該明白wraps
這個修飾器的作用了吧,就是將 被修飾的函式(wrapped) 的一些屬性值賦值給 修飾器函式(wrapper) ,最終讓屬性的顯示更符合我們的直覺。
相關推薦
python 裝飾器@wraps
預備知識 在瞭解wraps修飾器之前,我們首先要了解partial和update_wrapper這兩個函式,因為在wraps的程式碼中,用到了這兩個函式。 partial 首先說partial函式,在官方文件的描述中,這個函式的宣告如下:functools.partia
Python 裝飾器函式 wraps 利用快取查詢原理,加速遞迴
# 裝飾器函式 def foo(fn): def wrappers(): print("hello, %s" %fn.__name__) fn() print("bye, %s" %fn.__name__) return wrap
python裝飾器擴充套件之functools.wraps
我們知道函式被裝飾器,裝飾後,所有的屬性,以及內建函式就失效了。 原因是函式型別變成了warpper型別 示例1:不帶wraps裝飾器示例 def warfunc(func): def warpper(*args,**kwargs): print('wa
python裝飾器中@wraps作用--修復被裝飾後的函式名等屬性的改變
Python裝飾器(decorator)在實現的時候,被裝飾後的函式其實已經是另外一個函數了(函式名等函式屬性會發生改變),為了不影響,Python的functools包中提供了一個叫wraps的decorator來消除這樣的副作用。寫一個decorator的時候,最好在實現之前加上functools的wra
python裝飾器的wraps作用
rap docstring cst class too called ted rom style 不加: from functools import wraps def my_decorator(func): def wper(*args, **kwargs):
python 9-2 如何為被裝飾的函式儲存元資料,使用標準庫functools中的裝飾器wraps 裝飾內部包裹函式
9-2 如何為被裝飾的函式儲存元資料 解決方案: 使用標準庫functools中的裝飾器wraps 裝飾內部包裹函式,可以 制定將原函式的某些屬性,更新到包裹函式的上面 其實也可以通過 wr
021day--python裝飾器
輸出 for 購物 c函數 blog led 運行時 index 基本框架 一、裝飾器含義 裝飾器本質就是函數,為其它函數添加附加功能 二、裝飾器原則 1.不修改被修飾函數的代碼 2.不修改被修飾函數的調用方式 三、裝飾器知識 裝飾器 = 高階函數
python-裝飾器,類與對象,私有字段,析構,__call__,繼承,多繼承,接口
裝飾器 類與對象 私有字段 析構 __call__ 繼承 1、裝飾器執行流程裝飾器:將原函數替換為wrapper函數def outer()@outer --- func1作為參數傳入outer()def wrapper() --- wrapper()放入內存return wrapp
python--裝飾器詳解
blog 內容 class align fun turn strip 叠代器 ros Python---裝飾器詳解 定義: 本質上是一個函數。作用是用來裝飾另一個函數(即被裝飾函數),給被裝飾函數添加功能。前提是不能改變被裝飾函數的源代碼和調用方式。這樣的一個函數稱之為裝飾
Python裝飾器詳解
def 功能 style out return 裝飾器 代碼 方法 情況 首先是不使用裝飾器的情況,又需要在不修改原函數的情況話修改函數結果 1 def outer(func): 2 def inner(): 3 print("Hello")
python-裝飾器
驗證 定義 總結 是把 裝飾 ron highlight class 老板 一、介紹 首先我們先來看一個簡單的例子,在基礎平臺中有一個home()和tv()函數,在業務平臺中調用此函數時,給出了響應的打印內容: 基礎平臺: def home(): print(‘w
python---裝飾器
等等 value success star invalid user wrap net ces python裝飾器要點: 1. 裝飾器能夠給被裝飾的函數在不改變調用方式的情況下,增加功能,如日誌,計時等等 2. 被裝飾函數包含有不帶參數的,帶參數的 3. 裝飾器本身也分為不
python裝飾器
要去 什麽 改變 而且 python 入門 class 定義 博客 網上面有很多優秀的文章寫得很好,但是每個人的思路和接受的方式都不一樣,我選用了自己能看得懂再加上自己的理解寫了這篇博客,將分為多步實現對裝飾器的理解,作為新手入門級別,另外會在結束後,給上我認為優秀文章的鏈
python-------裝飾器
open isp over get spl 函數功能 style 先來 hide 一、簡單的裝飾器 1.為什麽要使用裝飾器呢? 裝飾器的功能:在不修改原函數及其調用方式的情況下對原函數功能進行擴展 裝飾器的本質:就是一個閉包函數 那麽我們先來看一個簡單的裝飾器:實現
python----------裝飾器應用練習
pla spa opened lose 多個 hdd lib 列表 -s 1.編寫裝飾器,為多個函數加上認證的功能(用戶的賬號密碼來源於文件),要求登錄成功一次,後續的函數都無需再輸入用戶名和密碼註意:從文件中讀出字符串形式的字典,可以用eval(‘{"name":"ego
Python 裝飾器
all *args 寫法 python的函數 日誌 方便 插入 3層 組合 裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象. 經常用於有切面需求的場景,比如:插入日誌、性能測試、事務處理
Python裝飾器主要用法
**kwargs div odi 功能 func erro utf spa 情況 #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = ‘人生入戲‘ user = "admin" passwd = "123
python裝飾器(2)
裝飾器 () 方式 cti 調用 st2 rgs 顯示 clas 1.以下代碼,bar作為參數被test2調用。bar的原代碼沒變,但調用方式從bar()變成test2(bar) 不符合裝飾器定義 1 __author__ = "csy" 2 3 def ba
python裝飾器(3)
urn python裝飾器 裝飾 int 裝飾器 func 實現 ret test 另一種實現方式: 1 __author__ = "csy" 2 3 def test2(func): 4 def test1(): 5 func()
Python # 裝飾器
als style div turn 通過 sta () pre ndt ### 現在我有一個簡單的myfunc函數,現在我想對myfunc函數增加功能。下面我們增加一個deco的功能。 import time def deco(func): startTime