python解答之裝飾器

來源:互聯網
上載者:User

標籤:inf   call   wrap   方式   簡單的   orm   函數傳參   time   war   

裝飾器,簡而言之就是在不改變原函數任何代碼(包括調用方式)的情況下為函數增加額外的功能。特殊之處在於裝飾器的傳回值也是一個函數。一、裝飾器介紹
下面先舉個簡單的栗子:
import time

def count_time(foo_func): def inner(): print("inner func start!") start_time = time.time() time.sleep(1) # 1s後執行 foo_func() end_time = time.time() print("the func cost:{:.2f}".format(end_time-start_time)) return inner

@count_time def foo(): # 利用裝飾器計算foo函數執行時間 print("foo execute done!!")

if __name__ == ‘__main__‘: foo() # 調用foo函數
既然說增加了裝飾器,那麼原函數的代碼和調用方式都沒改變。其中 @count_time 就等同於 foo = count_time(foo)
如果要給裝飾器傳參數。。如下: import time
def outer(name): def count_time(foo_func): def inner(): print("inner func start!") print("裝飾器傳進來的參數是:{}".format(name)) start_time = time.time() time.sleep(1) # 1s後執行 foo_func() end_time = time.time() print("the func cost:{:.2f}".format(end_time-start_time)) return inner return count_time

@outer(name="jack") def foo(): # 利用裝飾器計算foo函數執行時間 print("foo execute done!!")

if __name__ == ‘__main__‘: foo() # 調用foo函數
若要給裝飾器傳參數,只需要再給函數增加一層函數就行了。
但是由於使用裝飾器後會改變函數的一些內建變數比如__name__,__doc__。看栗子:
import time from functools import wraps

def count_time(foo_func): # @wraps(foo_func) def inner(): """ now in inner func """ print("inner func start!") start_time = time.time() time.sleep(1) # 1s後執行 foo_func() end_time = time.time() print("foo func cost:{:.2f}".format(end_time-start_time)) return inner

@count_time def foo(): """ now in foo func """ # 利用裝飾器計算foo函數執行時間 print("foo func doc is {}".format(foo.__doc__)) # 輸出 now in inner func print("foo func name is {}".format(foo.__name__)) # 輸出 inner print("foo execute done!!")

if __name__ == ‘__main__‘: foo() # 調用foo函數所以需要糾正回來,該如何呢?來
只需要引入functools模組下的wraps函數在inner函數上面使用@wraps(func),即再次裝飾下inner函數即可然後輸出語句會變為:print("foo func doc is {}".format(foo.__doc__)) # 輸出 now in foo funcprint("foo func name is {}".format(foo.__name__)) # 輸出 foo

要給被裝飾的函數傳參數:栗子如下: import time from functools import wraps

def count_time(foo_func): @wraps(func) def inner(*args, **kwargs): """ now in inner func """ print("inner func start!") start_time = time.time() time.sleep(1) # 1s後執行 foo_func(*args, **kwargs) end_time = time.time() print("foo func cost:{:.2f}".format(end_time-start_time)) return inner

@count_time def foo(name, age, *args, **kwargs): """ now in foo func """ # 利用裝飾器計算foo函數執行時間 print(name,age) print(args,kwargs) print("foo execute done!!")

if __name__ == ‘__main__‘: foo("jack", 21, "student", department="信工學院") # 調用foo函數
增加的地方有調用時傳了四個參數,分別是位置參數和關鍵字參數(最後一個是關鍵字參數,關鍵字參數必須在位置參數之後傳入)在裝飾器內部的inner函數的參數那裡增加了*args, **kwargs,和inner內部的func(*args, **kwargs)這裡args表示所有的位置參數都在args這個元組裡面kwargs表示所有的關鍵字參數都在args這個字典裡面

二、基於類實現的裝飾器看栗子 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): print( "say {}!".format(something))

say("hello")
輸出: [DEBUG]: enter function say() say hello!解答:如果用類來實現裝飾器的話,必須實作類別中的內建方法__init__和__call__這兩個方法其中__init__用來接收被裝飾函數的名字,__call__用來對函數進行裝飾以及增加額外的功能
若要給裝飾器傳參數。還是看栗子:class logging(object): def __init__(self, level=‘INFO‘): self.level = level
def __call__(self, func): # 接受函數 def wrapper(*args, **kwargs): print("[{level}]: enter function {func}()".format( level=self.level, func=func.__name__)) func(*args, **kwargs)
return wrapper # 返回函數

@logging(level=‘INFO‘)def say(something): print("say {}!".format(something))
say("hello")
這裡的調用就是給裝飾器傳參數。__init__方法參數接收的不再是被裝飾函數的函數名,而是裝飾器傳來的參數__call__方法參數接收被裝飾函數的函數名,裡面再嵌套一層函數用來接收裝飾函數傳的參數
最後,拓展一下wrapt這個裝飾器: import wrapt
@wrapt.decorator def logging(wrapped, instance, args, kwargs): # instance is must need print("[DEBUG]: enter {}()".format(wrapped.__name__)) return wrapped(*args, **kwargs)
@logging def say(something): pass
say("hello")
這樣看起來裝飾器就更加明了了,,不用在裝飾器內部再嵌套函數了。上面的寫法必須要按照上面的來其中wrapped就表示被裝飾的函數,若要給裝飾器傳參數,也是再嵌套一層就可以了。





python解答之裝飾器

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.