溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python中裝飾器代碼是怎么樣的

發(fā)布時間:2021-10-27 15:28:05 來源:億速云 閱讀:165 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“Python中裝飾器代碼是怎么樣的”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Python中裝飾器代碼是怎么樣的”這篇文章吧。

    一、理解裝飾器

    所有東西都是對象(函數(shù)可以當(dāng)做對象傳遞)
    由于函數(shù)也是一個對象,而且函數(shù)對象可以被賦值給變量,所以,通過變量也能調(diào)用該函數(shù)。

    def function_one():
        print("測試函數(shù)")
    #可以將一個函數(shù)賦值給一個變量,比如
    foo =function_one #這里沒有在使用小括號,因為我們并不是在調(diào)用function_one函數(shù),而是在將它放在foo變量里。
    foo()
    '''
    測試函數(shù)
    Process finished with exit code 0
    '''

    閉包的概念:

    1)函數(shù)嵌套

    2)內(nèi)部函數(shù)使用外部函數(shù)的變量

    3)外部函數(shù)的返回值為內(nèi)部函數(shù)

    示例:

    def outer_function(message):
        def inner_function():
            print(message)
        return inner_function
    func = outer_function("你好")
    func() #你好

    二、裝飾器原型

    裝飾器的作用就是 不修改源代碼以及原函數(shù)調(diào)用方式的情況下 給原函數(shù)增加新的功能。

    #將函數(shù)作為參數(shù)傳給另一個函數(shù)
    def decorator_function(original_function):
        def wrapper_function():
        	print('wrapper executed this before {}'.format(original_function.__name__))
            original_function()
        return wrapper_function
        '''
        返回wrapper_function而不是wrapper_function();這是因為當(dāng)你把一對小括號放在后面,這個函數(shù)就會執(zhí)行;
        然而如果你不放括號在它后面,那它可以被到處傳遞,并且可以賦值給別的變量而不去執(zhí)行它。
    	'''
    def display():
        print('display function ran')
    decorator_display = decorator_function(display)
    decorator_display()

    運(yùn)行結(jié)果:

    wrapper executed this before display
    display function ran
    Process finished with exit code 0

    1、不帶參數(shù)的裝飾器

    def decorator_function(original_function):
        def wrapper_function():
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function()
        return wrapper_function
    @decorator_function
    def display():  #等價于display =decorator_function(display)
        print('display function ran')
    display()

    運(yùn)行結(jié)果:

    wrapper executed this before display
    display function ran

    Process finished with exit code 0

    2.帶參數(shù)的被裝飾的函數(shù)

    def decorator_function(original_function):
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display()
    print('='*50)
    display_info('Michal',20)

    運(yùn)行結(jié)果:

    wrapper executed this before display
    display function ran
    ==================================================
    wrapper executed this before display_info
    display_info ran with arguments (Michal,20)

    Process finished with exit code 0

    運(yùn)行如下代碼會出現(xiàn)一個問題

    def decorator_function(original_function):
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info = decorator_function(display_info)
    print(display_info.__name__)

    wrapper_function

    Process finished with exit code 0

    輸出的應(yīng)該是display_info,這里的函數(shù)被wrapper_function替代了,重寫了我們函數(shù)的名字和注釋文檔(docstring)。Python中可以使用functools.wraps來解決這個問題。

    from functools import wraps
    def decorator_function(original_function):
        @wraps(original_function)
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info = decorator_function(display_info)
    print(display_info.__name__)

    運(yùn)行結(jié)果:

    display_info

    Process finished with exit code 0

    3.帶參數(shù)的裝飾器

    在函數(shù)中嵌入裝飾器

    from functools import wraps
    def logit(logfile='out.log'):
        def logging_decorator(func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打開logfile,并寫入內(nèi)容
                with open(logfile, 'a') as opened_file:
                    # 現(xiàn)在將日志打到指定的logfile
                    opened_file.write(log_string + '\n')
                return func(*args, **kwargs)
            return wrapped_function
        return logging_decorator
    @logit()
    def myfunc1():
        pass
    myfunc1()
    # Output: myfunc1 was called
    # 現(xiàn)在一個叫做 out.log 的文件出現(xiàn)了,里面的內(nèi)容就是上面的字符串
    @logit(logfile='func2.log')
    def myfunc2():
        pass
    myfunc2()
    # Output: myfunc2 was called
    # 現(xiàn)在一個叫做 func2.log 的文件出現(xiàn)了,里面的內(nèi)容就是上面的字符串

    4.使用類作為裝飾器

    class myDecorator(object):
         def __init__(self, f):
             print("inside myDecorator.__init__()")
             f() # Prove that function definition has completed
         def __call__(self):
             print("inside myDecorator.__call__()")
     
     @myDecorator
     def aFunction():
         print("inside aFunction()")
     
     print("Finished decorating aFunction()")
     
     aFunction()

    運(yùn)行結(jié)果:

    inside myDecorator.__init__()
    inside aFunction()
    Finished decorating aFunction()
    inside myDecorator.__call__()
    Process finished with exit code 0

    被裝飾后的函數(shù)aFunction()實際上已經(jīng)是類myDecorator的對象。當(dāng)再調(diào)用aFunction()函數(shù)時,實際上就是調(diào)用類myDecorator的對象,因此會調(diào)用到類myDecorator的__call__()方法。

    因此使用類作為裝飾器裝飾函數(shù)來對函數(shù)添加一些額外的屬性或功能時,一般會在類的__init__()方法中記錄傳入的函數(shù),再在__call__()調(diào)用修飾的函數(shù)及其它額外處理。

    class entryExit(object):
         def __init__(self, f):
             self.f = f
         def __call__(self):
             print("Entering", self.f.__name__)
             self.f()
             print("Exited", self.f.__name__)
     
     @entryExit
     def func1():
         print("inside func1()")
     
     @entryExit
     def func2():
         print("inside func2()")
     
     func1()
     func2()

    運(yùn)行結(jié)果:

    Entering func1
    inside func1()
    Exited func1
    Entering func2
    inside func2()
    Exited func2

    Process finished with exit code 0

    5.使用對象作為裝飾器

    空參:

    from functools import wraps
    class decorator_class:
        def __init__(self):
            print('執(zhí)行decorator_class類的__init__()方法')
        def __call__(self, original_function):
            print('執(zhí)行decorator_class類的__call__()方法')
            @wraps(original_function)
            def wrapped_function(*args, **kwargs):
                print('call method executed this before {}'.format(original_function.__name__))
                print('執(zhí)行' + original_function.__name__ + '()')
                original_function(*args, **kwargs)
                print(original_function.__name__ + '()執(zhí)行完畢')
            return wrapped_function
    @decorator_class()
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info('Michael',20)

    運(yùn)行結(jié)果如下:

    執(zhí)行decorator_class類的__init__()方法
    執(zhí)行decorator_class類的__call__()方法
    call method executed this before display_info
    執(zhí)行display_info()
    display_info ran with arguments (Michael,20)
    display_info()執(zhí)行完畢

    Process finished with exit code 0

    帶參數(shù):

    from functools import wraps
    class decorator_class:
        def __init__(self,arg1, arg2):
            print('執(zhí)行decorator_class類的__init__()方法')
            self.arg1 =arg1
            self.arg2=arg2
        def __call__(self, original_function):
            print('執(zhí)行decorator_class類的__call__()方法')
            @wraps(original_function)
            def wrapped_function(*args, **kwargs):
            	print('執(zhí)行wrapped_function()')
                print('call method executed this before {}'.format(original_function.__name__))
                print('裝飾器參數(shù):', self.arg1, self.arg2)
                print('執(zhí)行' + original_function.__name__ + '()')
                original_function(*args, **kwargs)
                print(original_function.__name__ + '()執(zhí)行完畢')
            return wrapped_function
    @decorator_class('Hello', 'World')
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info('Michael',20)

    運(yùn)行結(jié)果如下:

    執(zhí)行decorator_class類的__init__()方法
    執(zhí)行decorator_class類的__call__()方法
    執(zhí)行wrapped_function()
    call method executed this before display_info
    裝飾器參數(shù): Hello World
    執(zhí)行display_info()
    display_info ran with arguments (Michael,20)
    display_info()執(zhí)行完畢

    Process finished with exit code 0

    示例2:

    from functools import wraps
    class logit(object):
        def __init__(self, logfile='out.log'):
            self.logfile = logfile
        def __call__(self, func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打開logfile并寫入
                with open(self.logfile, 'a') as opened_file:
                    # 現(xiàn)在將日志打到指定的文件
                    opened_file.write(log_string + '\n')
                # 現(xiàn)在,發(fā)送一個通知
                self.notify()
                return func(*args, **kwargs)
            return wrapped_function
        def notify(self):
            # logit只打日志,不做別的
            pass
    @logit()
    def myfunc1():
        pass

    6.多層裝飾器的嵌套

    #裝飾器1
    def decorator1(func):
        #定義裝飾之后的函數(shù)
        def wrapper1():
            # 裝飾器1
            print('1-----裝飾1之前')
            # 調(diào)用基本函數(shù)
            func()
            # 擴(kuò)展功能2
            print('1-----裝飾1之后')
        return wrapper1
    #裝飾器2
    def decorator2(func):
        #定義裝飾之后的函數(shù)
        def wrapper2():
            # 裝飾器2
            print('2-----裝飾2之前')
            # 調(diào)用基本函數(shù)
            func()
            # 擴(kuò)展功能2
            print('2-----裝飾2之后')
        return wrapper2
    #基本函數(shù)
    @decorator2   # 第二步:test = decorator2(eat) = test2
    @decorator1   # 第一步:test = decorator1(eat)  = test1
    def test():
        print('測試')
    #調(diào)用函數(shù)
    test()

    運(yùn)行結(jié)果:

    2-----裝飾2之前
    1-----裝飾1之前
    測試
    1-----裝飾1之后
    2-----裝飾2之后

    Process finished with exit code 0

    以上是“Python中裝飾器代碼是怎么樣的”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI