python裝飾器理解 md

2021-10-01 16:27:14 字數 4693 閱讀 3192

裝飾器的順序

參考先來看個例子:

def foo(*args, **kwargs):

print 'args = ', args

print 'kwargs = ', kwargs

print '---------------------------------------'

if __name__ == '__main__':

foo(1,2,3,4)

foo(a=1,b=2,c=3)

foo(1,2,3,4, a=1,b=2,c=3)

foo('a', 1, none, a=1, b='2', c=3)

輸出結果如下:

args = (1, 2, 3, 4)

kwargs = {}

---------------------------------------

args = ()

kwargs =

---------------------------------------

args = (1, 2, 3, 4)

kwargs =

---------------------------------------

args = ('a', 1, none)

kwargs =

---------------------------------------

可以看到,這兩個是python中的可變引數。args表示任何多個無名引數,它是乙個tuple;**kwargs表示關鍵字引數,它是乙個dict。並且同時使用args和kwargs時,必須*args引數列要在kwargs前,像foo(a=1, b=『2』, c=3, a』, 1, none, )這樣呼叫的話,會提示語法錯誤「syntaxerror: non-keyword arg after keyword arg」。

def use_logging(func):

logging.warning("%s is running" % func.__name__)

return func(*args)

@use_logging

def foo():

print("i am foo")

@use_logging

def bar():

print('i am bar')

# bar=use_logging(bar)

bar()

foo()

這裡的大概邏輯:

有個功能(logging.warning),兩個函式foo和bar都會用到;

但是又不想多寫,於是寫成下面形式了:

在呼叫foo的時候,執行了logging.warning這個功能;

在呼叫bar的時候,也執行了logging.warning這個功能;

但是只寫了一遍!

def use_logging(level):

def decorateor(func):

if level =="warn":

logging.warning("%s is running" % func.__name__)

else:

print("hello !")

return func(*args)

return decorateor

@use_logging(level="warn")

def foo(name="foo"):

print("i am %s"%name)

@use_logging(level="hello")

def bar(name="bar"):

print('i am %s'%name)

foo()

bar()

帶引數的裝飾器:

大體邏輯同上;

use_logging是允許帶引數的裝飾器。它實際上是對原有裝飾器的乙個函式封裝,並返回乙個裝飾器。

我們可以將它理解為乙個含有引數的閉包。當我 們使用@use_logging(level=「warn」)呼叫的時候,

python能夠發現這一層的封裝,並把引數傳遞到裝飾器的環境中。

class foo(object):

def __init__(self, func):

self._func = func

def __call__(self):

print('class decorator runing')

self._func()

print('class decorator ending')

@foo

def bar():

print ('bar')

@foo

def hi():

print("hi")

bar()

hi()

類裝飾器:

再來看看類裝飾器,相比函式裝飾器,類裝飾器具有靈活度大、高內聚、封裝性等優點。

使用類裝飾器還可以依靠類內部的__call__方法,當使用 @ 形式將裝飾器附加到函式上時,就會呼叫此方法。

缺點:使用裝飾器極大地復用了**,但是他有乙個缺點就是原函式的元資訊不見了,

比如函式的docstring、name、引數列表,先看例子:

def logged(func):

def with_logging(*args, **kwargs):

print(func.__name__ + " was called")

return func(*args, **kwargs)

return with_logging

@logged

def f(x):

return x+x*x

f = logged(f)

"""with_logging was called

f was called

"""def f(x):

return x+x*x

f = logged(f)

"""f was called

"""f(2)

這個問題就比較嚴重的,好在我們有functools.wraps,wraps本身也是乙個裝飾器,它能把原函式的元資訊拷貝到裝飾器函式中,這使得裝飾器函式也有和原函式一樣的元資訊了。

from functools import wraps

def logged(func):

@wraps(func)

def with_logging(*args, **kwargs):

print(func.__name__ + " was called")

return func(*args, **kwargs)

return with_logging

@logged

def f(x):

print("this is f(x)")

return x + x * x

f(2)

print("******************************===")

print(f.__name__)

print("******************************===")

print(f.__doc__)

@a

@b@c

def f ():

等效於:

f = a(b(c(f)))
當裝飾器也需要參入引數時我們需要給裝飾器再加一層函式,

此時裝飾器接受到的方法需要進入第二層函式進行接受,

第一層需要接受裝飾器自己的引數

user, password = 'db', '12345'

def login(login_type):

usernameinput = input("username:").strip()

passwordinput = input("password:").strip()

if login_type == "local":

if user == usernameinput and password == passwordinput:

print("login successful")

res = func(*agr1, **kwargs) # 接受返回結果

return res

else:

print("login fail")

elif login_type == "ldap":

print("遠端登入")

def index():

print("welcome to index page")

@login(login_type="local") # 對裝飾分類

def home():

print("welcome to home page")

return "from home"

@login(login_type="ldap") # 對裝飾分類

def blog():

print("welcome to blog page")

index()

print(home())

blog()

python裝飾器理解 python裝飾器理解

裝飾器 在不改變原函式的 和呼叫方法的基礎上,給原函式增加額外的功能 理解宣告 為了方便理解,以下例子採用最簡潔的函式和新增的功能 給原函式新增乙個執行時間 import time def timer func def inner func return inner timer func timer...

python裝飾器 理解Python裝飾器

在python中,對於乙個函式,若想在其執行前後做點什麼,那麼裝飾器是再好不過的選擇,話不多說,上 usr bin env coding utf 8 script 01.py author howie from functools import wraps def decorator func wr...

python裝飾器理解 python裝飾器的理解

python裝飾器應該算是面試常考到的用點,之前在flask的應用中也是會常常用到,抽空仔細看書查資料理解了下裝飾器的概念,通過自己的理解記憶,應該對這個概念會有乙個大致上具體的了解。閉包說起python裝飾器,我們應該不得不談談閉包的概念。我對閉包的理解是,當函式存在巢狀,子函式呼叫了父函式的變數...