需求:運行函數時獲得該函數的名稱 |
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函數名稱