python之裝飾器


裝飾器作用:在不改變原代碼的情況下增強原代碼的功能

裝飾器返回的是可調用的(函數)對象,可調用的(函數)對象,可調用的(函數)對象。

判斷函數是否為閉包可通過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')

當出現同時多個裝飾器時,裝飾器會從下往上執行

  1. @outer3 func() = outer3(func) --> 返回inner1
  2. @outer2 outer2(func) = outer2(outer3(func)) --> outer3(func)== func 被傳入outer2
  3. @outer1 outer1(func) = outer1(outer2(outer3(func))) --> outer2(outer3(func)) == func 被傳入outer1

所以實際執行順序為

  1. outer1(func): --> print('inner1 first')
  2. outer1(func): --> func() == outer2(outer3(func))
  3. outer2(func): --> print('inner2 first')
  4. outer2(func): --> func() == outer3(func)
  5. outer3(func): --> print('inner3 first')
  6. outer3(func): --> func() == func() (裝飾器外定義的)
  7. func(): --> print('Hello World')
  8. outer3(func): --> print('inner3 second')
  9. outer2(func): --> print('inner2 second')
  10. 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')


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM