Python核心編程之裝飾器

引入:

需求:運行函數時獲得該函數的名稱
版本一:直接print函數名稱
缺陷:當函數名稱發生改變時,print中的內容也須要改變。硬編碼
import inspect
'''
轉載:https://www.cnblogs.com/cicaday/p/python-decorator.html
需求:運行函數時獲得該函數的名稱
版本一:直接print函數名稱
缺陷:當函數名稱發生改變時,print中的內容也須要改變。硬編碼
'''def say_hello():
    print("hello")
def say_goodbye():
    print("goodbye")

if __name__ == "__main__":
    say_hello()
    say_goodbye()
版本二:調用inspect模塊中的stack()方法,獲取函數名稱
缺陷:調用debug()方法屢次
import inspect
'''
需求:運行函數時獲得該函數的名稱
版本二:調用inspect模塊中的stack()方法,獲取函數名稱
缺陷:調用debug()方法屢次
'''
def debug():
    caller_name = inspect.stack()
    print("caller_name: " + caller_name[1][3])

def say_hello():
    debug()
    print("hello")
def say_goodbye():
    debug()
    print("goodbye")

if __name__ == "__main__":
    say_hello()
    say_goodbye()

裝飾器:html

版本三:裝飾器 ---------裝飾器:裝飾器的做用就是爲已經存在的函數或對象添加額外的功能。 裝飾器本質上是一個Python函數,它可讓其餘函數 在不須要作任何代碼變更的前提下增長額外功能,裝飾器的返回值 也是一個函數對象。它常常用於有切面需求的場景, 好比:插入日誌、性能測試、事務處理、緩存、權限校驗等場景。 裝飾器是解決這類問題的絕佳設計,有了裝飾器, 咱們就能夠抽離出大量與函數功能自己無關的雷同代碼並繼續重用。 '''

1、不帶參數的裝飾器python

import inspect
'''
需求:運行函數時獲得該函數的名稱
版本四:裝飾器
---------裝飾器:裝飾器的做用就是爲已經存在的函數或對象添加額外的功能。
    裝飾器本質上是一個Python函數,它可讓其餘函數
    在不須要作任何代碼變更的前提下增長額外功能,裝飾器的返回值
    也是一個函數對象。它常常用於有切面需求的場景,
    好比:插入日誌、性能測試、事務處理、緩存、權限校驗等場景。
    裝飾器是解決這類問題的絕佳設計,有了裝飾器,
    咱們就能夠抽離出大量與函數功能自己無關的雷同代碼並繼續重用。
'''
def debug(func):
    def wrapper():
        print("callner_name:" + func.__name__)
        return func()
    return wrapper
@debug
def say_hello():
    print("hello")

@debug
def say_goodbye():
    print("goodbye")

if __name__ == "__main__":
    say_hello()
    print('say_hello()實際調用的函數:'+ say_hello.__name__)
    say_goodbye()
    print('say_goodbye()實際調用的函數:'+ say_goodbye.__name__)
'''運行結果
callner_name:say_hello
hello
say_hello()實際調用的函數:wrapper
callner_name:say_goodbye
goodbye
say_goodbye()實際調用的函數:wrapper
'''

2、帶參數的裝飾器緩存

import inspect
'''
裝飾器傳參數
理解*args, **kwargs: splat運算符* **
*args: 將傳入的位置參數打包成元組(可變參數)
**kwargs: 將傳入的關鍵字參數打包成字典(可選參數)

到這裏已經掌握了初級裝飾器的寫法
'''
def add_sum(*args):
    print(args)
    print(type(args))

def add_s(**kwargs):
    print(kwargs)
    print(type(kwargs))
    for key, value in kwargs.items():
        print(f"{key}:{value}")

def debug(func):
    def wrapper(*args, **kwargs):  # 宇宙無敵參數
        print("callner_name:" + func.__name__)
        return func(*args, **kwargs)
    return wrapper
@debug
def say_hello(somthing):
    print(f"hello{somthing}")

@debug
def say_goodbye(something):
    print(f"goodbye{something}")


if __name__ == "__main__":
    add_sum(1, 2, 3, 4, 5)
    add_s(a=1, b=2, c=3)
    print(*[1, 2, 3, 4])
    print(*{'a': 1, 'b': 2, 'c': 3})
    say_hello('!')
    say_goodbye('!')
'''運行結果
(1, 2, 3, 4, 5)
<class 'tuple'>
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>
a:1
b:2
c:3
1 2 3 4
a b c
callner_name:say_hello
hello!
callner_name:say_goodbye
goodbye!
'''

3、不帶參數的類裝飾器app

import inspect
'''
基於類實現的裝飾器(不帶參數):callable 能夠調用
    裝飾器函數實際上是這樣一個接口約束,
它必須接受一個callable對象做爲參數,
而後返回一個callable對象。
在Python中通常callable對象都是函數,
但也有例外。只要某個對象重載了__call__()方法,
那麼這個對象就是callable的。
'''
class Test():
    def __call__(self, *args, **kwargs):
        print('call me')

class logging(object):
    def __init__(self, func):
        self.func = func

    # 內置方法
    def __call__(self, *args, **kwargs):
        print("[DEBUG]: enter function {func}()".format(
            func=self.func.__name__))
        return self.func(*args, **kwargs)
@logging
def say(something='Toney'):
    print("say {}!".format(something))

# say = logging(say)
# say(something='Toney')  --> 執行內置方法
if __name__ == "__main__":
   t = Test()
   t()
   say()
'''運行結果
call me
[DEBUG]: enter function say()
say Toney!
'''
 

4、帶參數的類裝飾器函數

import inspect
'''
帶參數的類裝飾器
'''
class logging(object):
    def __init__(self, level):
        self.level = level

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("[DEBUG]: enter function {level}()".format(
                level=self.level))
            func(*args, **kwargs)
        return wrapper
@logging(level = 'INFO')
def say(something='Toney'):
    print("say {}!".format(something))
# say = logging(level = 'INFO')
# say = say(something='Toney') --> say = wrapper
if __name__ == "__main__":
   say()
'''運行結果
[DEBUG]: enter function INFO()
say Toney!
'''
需求:運行函數時獲得該函數的名稱
版本一:直接print函數名稱
相關文章
相關標籤/搜索