Python中裝飾器兼容加括號和不加括號的寫法詳解
使用Django的時候,我發(fā)現(xiàn)一個很神奇的裝飾器: @login_required, 這是控制一個view的權(quán)限的,比如一個視圖必須登錄才可以訪問,可以這樣用:
@login_required def my_view(request): ... return render(...)
同時,如果要達到這樣一種效果:如果用戶沒有登錄,那么就把用戶重定向到登錄界面,可以這樣用:
@login_required(login_url='/accounts/login/') def my_view(request): ... return render(...)
所以這個裝飾器可以帶括號寫,又可以不帶括號寫。很神奇有沒有。正常的接收參數(shù)的裝飾器,就算沒參數(shù)也應(yīng)該寫成@login_required的
好奇去查了一下,在stackoverflow找到一種實現(xiàn),挺有意思的。先曬出答案:
def doublewrap(f): ''' a decorator decorator, allowing the decorator to be used as: @decorator(with, arguments, and=kwargs) or @decorator ''' @wraps(f) def new_dec(*args, **kwargs): if len(args) == 1 and len(kwargs) == 0 and callable(args[0]): # actual decorated function return f(args[0]) else: # decorator arguments return lambda realf: f(realf, *args, **kwargs) return new_dec
使用起來很簡單,只要給裝飾器用@doublewrap裝飾一下,這個裝飾器就支持寫括號和不寫括號兩種寫法了。
def test_doublewrap(): from util import doublewrap from functools import wraps @doublewrap def mult(f, factor=2): '''multiply a function's return value''' @wraps(f) def wrap(*args, **kwargs): return factor*f(*args,**kwargs) return wrap # try normal @mult def f(x, y): return x + y # try args @mult(3) def f2(x, y): return x*y # try kwargs @mult(factor=5) def f3(x, y): return x - y assert f(2,3) == 10 assert f2(2,5) == 30 assert f3(8,1) == 5*7
原理也不難,只有短短不到10行代碼。
裝飾器我們都知道,是用來處理一個函數(shù),返回一個新的函數(shù)的(如果你不理解裝飾器,可以看一下這個經(jīng)典的解釋)。
new_func = decorator(func)
我們使用的,就是被裝飾器裝飾的新函數(shù)了。裝飾器只是一個語法糖,其實它也是一個函數(shù),給它傳入一個函數(shù)作為參數(shù),就返回一個新的函數(shù)。那么既然裝飾器也是一個函數(shù),我們就可以用裝飾器裝飾這個函數(shù)。也就是,“裝飾器的裝飾器”。
裝飾器第一個參數(shù)肯定是原函數(shù),如果裝飾器可以接收參數(shù)的話,要么第一個參數(shù)是原函數(shù),后面跟別的參數(shù);要么就只有原函數(shù)一個參數(shù)。所以,我們這個“裝飾器的裝飾器”做的事情就是,判斷裝飾器接收的參數(shù),如果只有一個并且第一個參數(shù)是可調(diào)用的(callable),那么這就是一個無參數(shù)的裝飾器(不需要加括號)。如果還有別的參數(shù),就返回一個生成裝飾器的函數(shù)(decorator_maker)。
裝飾器是一個函數(shù)。裝飾器被裝飾過之后,這個裝飾器運行之前就會先運行裝飾器的裝飾器的代碼,也就是我們的doublewrapp。然后返回值可能是一個裝飾器,也可能是一個裝飾器的maker(有參數(shù)的裝飾器),然后裝飾器再執(zhí)行,裝飾原函數(shù)。
這里有點繞,因為本來裝飾器里面一般就會有三四層函數(shù)了,(maker, decorator, wrapper, realfunc),再加上一個裝飾器的裝飾器,會有點理解困難。如果理解不了,最好不要對著網(wǎng)上的博文(包括本文)企圖格物致知了,多去看看代碼,多寫一寫。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
參考資料
How to create a Python decorator that can be used either with or without parameters?
相關(guān)文章
python3在各種服務(wù)器環(huán)境中安裝配置過程
這篇文章主要介紹了python3在各種服務(wù)器環(huán)境中安裝配置過程,源碼包編譯安裝步驟詳解,本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下2022-01-01
Python pandas自定義函數(shù)的使用方法示例
這篇文章主要介紹了Python pandas自定義函數(shù)的使用方法,結(jié)合實例形式分析了pandas模塊相關(guān)自定義函數(shù)數(shù)值運算操作技巧,需要的朋友可以參考下2019-11-11
Python實現(xiàn)連接dr校園網(wǎng)示例詳解
在校園里認證上網(wǎng)很麻煩需要web輸入賬號密碼有時還會忘記web地址,所以為了解決這一問題,本文將為大家介紹通過Python實現(xiàn)校園網(wǎng)的連接,快來跟隨小編一起學(xué)習(xí)吧2021-11-11
python使用__slots__讓你的代碼更加節(jié)省內(nèi)存
如果要限制添加的屬性,例如,Student類只允許添加 name、gender和score 這3個屬性,就可以利用Python的一個特殊的slots來實現(xiàn)。這篇文章主要給大家介紹了關(guān)于python如何使用__slots__讓你的代碼更加節(jié)省內(nèi)存的相關(guān)資料,需要的朋友可以參考下2018-09-09

