裝飾器作用:在不改變原代碼的情況下增強原代碼的功能
裝飾器返回的是可調用的(函數)對象,可調用的(函數)對象,可調用的(函數)對象。
判斷函數是否為閉包可通過func的__closure__查看,如里邊帶__cell__元素,那么可以認為這個函數是閉包.
而__cell__里邊包含着函數內部所引用的非全局的變量
不要被@迷惑
@只是一個語法糖
1.
def func1(func):
print(1)
@func1
def func2():
pass
func2()
2.
def func1(func):
print(1)
def func2():
pass
func1(func2)
'''
第一段代碼中的func2()和第二段代碼中的func1(func2)是等價的
@只是一個語法糖,當使用
@func1
def func2()
pass
func2 會被重新定義成func1(func2)
相當於
a = 1000
a = a + 1
這是a已經不再是1000了 而是通過a+1得出來的結果1001 而1000早已經被銷毀
'''
裝飾器的使用:
情景1:實現用戶訪問某些網頁時,需要先登錄,如果沒登錄就重定向到登錄界面
def login_required(func):
def wrapper(*args, *kwargs):
if 'user is login':
result = func()
else:
print('please login first')
result = redirect(login_url)
return result
return wrapper
@login_required
def func():
pass
這時每次調用func時 就會先判斷用戶是否已經登錄,然后再執行func函數里邊對應的操作
情景2:但是有時候login_url 並不是固定的 所以我們需要在使用時自定義返回的頁面
def login_required(login_url='login.html')
def outer(func):
def wrapper(*args, *kwargs):
if 'user is login':
result = func()
else:
print('please login first')
result = redirect(login_url)
return result
return wrapper
return outer
@login_required(login_url='login2.html')
def func():
pass
這時候,只需要在最外邊再定義一層函數來接收調用裝飾器時所傳遞的參數就可以
這時候的func = login_required(login_url='login2.html')(func)(*args, *kwargs)
同時使用多個裝飾器:
def outer1(func):
def inner1():
print('inner1 first')
func()
print('inner1 second')
return inner1
def outer2(func):
def inner2():
print('inner2 first')
func()
print('inner2 second')
return inner2
def outer3(func):
def inner3():
print('inner3 first')
func()
print('inner3 second')
return inner3
@outer1
@outer2
@outer3
def func():
print('Hello World')
當出現同時多個裝飾器時,裝飾器會從下往上執行
- @outer3 func() = outer3(func) --> 返回inner1
- @outer2 outer2(func) = outer2(outer3(func)) --> outer3(func)== func 被傳入outer2
- @outer1 outer1(func) = outer1(outer2(outer3(func))) --> outer2(outer3(func)) == func 被傳入outer1
所以實際執行順序為
- outer1(func): --> print('inner1 first')
- outer1(func): --> func() == outer2(outer3(func))
- outer2(func): --> print('inner2 first')
- outer2(func): --> func() == outer3(func)
- outer3(func): --> print('inner3 first')
- outer3(func): --> func() == func() (裝飾器外定義的)
- func(): --> print('Hello World')
- outer3(func): --> print('inner3 second')
- outer2(func): --> print('inner2 second')
- outer1(func): --> print('inner1 second')
用類來做裝飾器
實現@X
@X func = X(func) --> init
@X() func = X(func)() --> init call
class DecoClass:
def __init__(self, func):
self.func = func
def __call__(self):
print('執行func前')
result = self.func()
print('執行func后')
return result
@DecoClass
def func():
print('Hello World')
實現@DecoClass(args)
class DecoClass:
def __init__(self, args):
self.arg = args
def __call__(self, func):
def inner(*args, **kwargs):
print(self.arg)
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
@DecoClass(1)
def func(*args, **kwargs):
print('Hello World')
使用類當裝飾器時,要注意__init__ 和__call__,需要分清他們分別在什么情況下調用,接受的是又什么參數
@DecoClass(1) 1其實是被__init__接收的 而func則被__call__接收
@DecoClass(1) func = DecoClass(1)(func) DecoClass(1)初始化 返回的是實例 實例() 則調用__call__
實現@DecoClass.deco
class DecoClass:
#[@classmethod|@staticmethod]
def deco(func):
def inner(*args, **kwargs):
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
@DecoClass.deco
def func():
print('Hello World')
實現@DecoClass.deco(1)
class DecoClass:
def deco(arg):
def outer(func):
def inner(*args, **kwargs):
print(arg)
print('執行func前')
result = func()
print('執行func后')
return result
return inner
return deco
@DecoClass.deco(1)
def func():
print('Hello World')
實現@decoclass
class DecoClass:
def __call__(self, func):
def inner(*args, **kwargs):
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
decoclass = DecoClass()
@decoclass
def func():
print('Hello World')
實現@decoclass(args)
class DecoClass:
def __call__(self, *args, **kwargs):
def outer(func):
print(args)
def inner(*args, **kwargs):
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
return outer
decoclass = DecoClass()
@decoclass(1)
def func():
print('Hello World')
實現@decoclass.deco
class DecoClass:
def deco(self, func):
def inner(*args, **kwargs):
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
decoclass = DecoClass()
@decoclass.deco
def func():
print('Hello World')
實現@decoclass.deco(args)
class DecoClass:
def deco(self, *args, **kwargs):
def outer(func):
print(args)
def inner(*args, **kwargs):
print('執行func前')
result = func(*args, **kwargs)
print('執行func后')
return result
return inner
return outer
decoclass = DecoClass()
@decoclass.deco(1)
def func():
print('Hello World')
