python的函式是物件
要理解裝飾器,首先,你必須明白,在python中,函式是物件. 這很重要.
簡單例子來理解為什麼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
def shout(word="yes"): return word.capitalize()+"!" print shout() # outputs : 'Yes!' # 作為一個物件,你可以講函式賦值給另一個物件 scream = shout # 注意到這裡我們並沒有使用括號:我們不是呼叫函式,而是將函式'shout'賦給變數'scream' # 這意味著,你可以通過'scream'呼叫'shout' print scream() # outputs : 'Yes!' # 不僅如此,你可以刪除老的名稱'shout',但是通過'scream'依舊可以訪問原有函式 del shout try: print shout() except NameError, e: print e #outputs: "name 'shout' is not defined" print scream() # outputs: 'Yes!' |
好了,記住這點,我們將會很快用到它.
Python函式另一個有趣的特性是,函式可以被定義在另一個函式裡面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
def talk(): # 你可以定義一個函式 def whisper(word="yes"): return word.lower()+"..." # ... 並且立刻呼叫 print whisper() # 每次當你呼叫"talk", 都會定義"whisper" # 並且在"talk"中被呼叫 talk() # outputs: # "yes..." #但是在"talk"外部,函式"whisper"不存在! try: print whisper() except NameError, e: print e #outputs : "name 'whisper' is not defined"* |
函式引用
好了,到這裡了,接下來是有意思的部分,我們剛才看到 函式是物件,然後:
1.函式可以賦值給一個變數
2.函式可以定義在另一個函式內部
即,這也意味著一個函式可以返回另一個函式:-),讓我們來看另一段程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
def getTalk(type="shout"): # 定義函式 def shout(word="yes"): return word.capitalize()+"!" def whisper(word="yes") : return word.lower()+"..."; # 返回函式 if type == "shout": # 沒有使用"()", 並不是要呼叫函式,而是要返回函式物件 return shout else: return whisper # 如何使用? # 將函式返回值賦值給一個變數 talk = getTalk() # 我們可以列印下這個函式物件 print talk #outputs : function shout at 0xb7ea817c> # 這個物件是函式的返回值 print talk() #outputs : Yes! # 不僅如此,你還可以直接使用之 print getTalk("whisper")() #outputs : yes... |
但是稍等,如果你可以返回一個函式,那麼你也可以將函式作為引數傳遞
1 2 3 4 5 6 7 8 |
def doSomethingBefore(func): print "I do something before then I call the function you gave me" print func() doSomethingBefore(scream) #outputs: #I do something before then I call the function you gave me #Yes! |
好了,現在你已經瞭解要理解裝飾器的每件事.
裝飾器就是封裝器,可以讓你在被裝飾函式之前或之後執行程式碼,而不必修改函式本身
手工裝飾器
如何書寫一個裝飾器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# 裝飾器是一個以另一個函式為引數的函式 def my_shiny_new_decorator(a_function_to_decorate): # 在這裡,裝飾器定義一個函式: 包裝器. # 這個函式將原始函式進行包裝,以達到在原始函式之前、之後執行程式碼的目的 def the_wrapper_around_the_original_function(): # 將你要在原始函式之前執行的程式碼放到這裡 print "Before the function runs" # 呼叫原始函式(需要帶括號) a_function_to_decorate() # 將你要在原始函式之後執行的程式碼放到這裡 print "After the function runs" # 程式碼到這裡,函式‘a_function_to_decorate’還沒有被執行 # 我們將返回剛才建立的這個包裝函式 # 這個函式包含原始函式及要執行的附加程式碼,並且可以被使用 return the_wrapper_around_the_original_function # 建立一個函式 def a_stand_alone_function(): print "I am a stand alone function, don't you dare modify me" a_stand_alone_function() #outputs: I am a stand alone function, don't you dare modify me # 好了,在這裡你可以裝飾這個函式,擴充套件其行為 # 將函式傳遞給裝飾器,裝飾器將動態地將其包裝在任何你想執行的程式碼中,然後返回一個新的函式 a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function) # 呼叫新函式,可以看到裝飾器的效果 a_stand_alone_function_decorated() #outputs: #Before the function runs #I am a stand alone function, don't you dare modify me #After the function runs |
到這裡,或許你想每次呼叫a_stand_alone_function都使用a_stand_alone_function_decorated替代之
很簡單,只需要將a_stand_alone_function用my_shiny_new_decorator裝飾返回
1 2 3 4 5 6 7 8 |
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function) a_stand_alone_function() #outputs: #Before the function runs #I am a stand alone function, don't you dare modify me #After the function runs # 這就是裝飾器做的事情! |
裝飾器闡述
前面的例子,使用裝飾器語法
1 2 3 4 5 6 7 8 9 |
@my_shiny_new_decorator def another_stand_alone_function(): print "Leave me alone" another_stand_alone_function() #outputs: #Before the function runs #Leave me alone #After the function runs |
是的,就是這麼簡單. @decorator是下面程式碼的簡寫
1 |
nother_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function) |
裝飾器只是 裝飾器模式的python實現
python程式碼中還存在其他幾個經典的設計模式,以方便開發,例如迭代器iterators
當然,你可以累加裝飾器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
def bread(func): def wrapper(): print "/''''''>" func() print "______/>" return wrapper def ingredients(func): def wrapper(): print "#tomatoes#" func() print "~salad~" return wrapper def sandwich(food="--ham--"): print food sandwich() #outputs: --ham-- #累加兩個裝飾器 sandwich = bread(ingredients(sandwich)) sandwich() #outputs: #/''''''> # #tomatoes# # --ham-- # ~salad~ #______/> |
使用python裝飾器語法
1 2 3 4 5 6 7 8 9 10 11 12 |
@bread @ingredients def sandwich(food="--ham--"): print food sandwich() #outputs: #''''''> # #tomatoes# # --ham-- # ~salad~ # |
裝飾器位置的順序很重要
1 2 3 4 5 6 7 8 9 10 11 12 |
@ingredients @bread def strange_sandwich(food="--ham--"): print food strange_sandwich() #outputs: ##tomatoes# #''''> # --ham-- # # ~salad~' |
最後回答問題
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# bold裝飾器 def makebold(fn): def wrapper(): # 在前後加入標籤 return "" + fn() + "" return wrapper # italic裝飾器 def makeitalic(fn): def wrapper(): # 加入標籤 return "" + fn() + "" return wrapper @makebold @makeitalic def say(): return "hello" print say() #outputs: hello # 等價的程式碼 def say(): return "hello" say = makebold(makeitalic(say)) print say() #outputs: hello |
好了,到這裡你可以高興地離開了,或者來看下一些裝飾器高階的用法
向裝飾器函式傳遞引數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 這不是黑魔法,你只需要讓包裝傳遞引數: def a_decorator_passing_arguments(function_to_decorate): def a_wrapper_accepting_arguments(arg1, arg2): print "I got args! Look:", arg1, arg2 function_to_decorate(arg1, arg2) return a_wrapper_accepting_arguments # 當你呼叫裝飾器返回的函式,實際上是呼叫包裝函式,所以給包裝函式傳遞引數即可將引數傳給裝飾器函式 @a_decorator_passing_arguments def print_full_name(first_name, last_name): print "My name is", first_name, last_name print_full_name("Peter", "Venkman") # outputs: #I got args! Look: Peter Venkman #My name is Peter Venkman |
裝飾方法
Python中物件的方法和函式是一樣的,除了物件的方法首個引數是指向當前物件的引用(self)。這意味著你可以用同樣的方法構建一個裝飾器,只是必須考慮self
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def method_friendly_decorator(method_to_decorate): def wrapper(self, lie): lie = lie - 3 # very friendly, decrease age even more :-) return method_to_decorate(self, lie) return wrapper class Lucy(object): def __init__(self): self.age = 32 @method_friendly_decorator def sayYourAge(self, lie): print "I am %s, what did you think?" % (self.age + lie) l = Lucy() l.sayYourAge(-3) #outputs: I am 26, what did you think? |
當然,你可以構造一個更加通用的裝飾器,可以作用在任何函式或物件方法上,而不必關係其引數
使用
1 |
*args, **kwargs |
如下程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
def a_decorator_passing_arbitrary_arguments(function_to_decorate): # 包裝函式可以接受任何引數 def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs): print "Do I have args?:" print args print kwargs # 然後你可以解開引數, *args,**kwargs # 如果你對此不是很熟悉,可以參考 http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ function_to_decorate(*args, **kwargs) return a_wrapper_accepting_arbitrary_arguments @a_decorator_passing_arbitrary_arguments def function_with_no_argument(): print "Python is cool, no argument here." function_with_no_argument() #outputs #Do I have args?: #() #{} #Python is cool, no argument here. @a_decorator_passing_arbitrary_arguments def function_with_arguments(a, b, c): print a, b, c function_with_arguments(1,2,3) #outputs #Do I have args?: #(1, 2, 3) #{} #1 2 3 @a_decorator_passing_arbitrary_arguments def function_with_named_arguments(a, b, c, platypus="Why not ?"): print "Do %s, %s and %s like platypus? %s" % (a, b, c, platypus) function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!") #outputs #Do I have args ? : #('Bill', 'Linus', 'Steve') #{'platypus': 'Indeed!'} #Do Bill, Linus and Steve like platypus? Indeed! class Mary(object): def __init__(self): self.age = 31 @a_decorator_passing_arbitrary_arguments def sayYourAge(self, lie=-3): # You can now add a default value print "I am %s, what did you think ?" % (self.age + lie) m = Mary() m.sayYourAge() #outputs # Do I have args?: #(__main__.Mary object at 0xb7d303ac>,) #{} #I am 28, what did you think? |
向裝飾器傳遞引數
好了,現在你或許會想是否可以向裝飾器本身傳遞引數
裝飾器必須使用函式作為引數,所以這看起來會有些複雜,你不能直接傳遞引數給裝飾器本身
在開始處理這個問題前,看一點提醒
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 裝飾器是普通的方法 def my_decorator(func): print "I am a ordinary function" def wrapper(): print "I am function returned by the decorator" func() return wrapper # 所以,你可以不通過@呼叫它 def lazy_function(): print "zzzzzzzz" decorated_function = my_decorator(lazy_function) #outputs: I am a ordinary function # It outputs "I am a ordinary function", because that's just what you do: # 呼叫一個函式,沒有什麼特別 @my_decorator def lazy_function(): print "zzzzzzzz" #outputs: I am a ordinary function |
上面兩個形式本質上是相同的, “my_decorator” 被呼叫.所以當你使用”@my_decorator”,告訴python一個函式被變數”my_decorator”標記
這十分重要,因為你提供的標籤直接指向裝飾器…或者不是,繼續
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# 宣告一個用於建立裝飾器的函式 def decorator_maker(): print "I make decorators! I am executed only once: "+ "when you make me create a decorator." def my_decorator(func): print "I am a decorator! I am executed only when you decorate a function." def wrapped(): print ("I am the wrapper around the decorated function. " "I am called when you call the decorated function. " "As the wrapper, I return the RESULT of the decorated function.") return func() print "As the decorator, I return the wrapped function." return wrapped print "As a decorator maker, I return a decorator" return my_decorator # Let's create a decorator. It's just a new function after all. # 建立一個裝飾器,本質上只是一個函式 new_decorator = decorator_maker() #outputs: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator # 使用裝飾器裝飾函式 def decorated_function(): print "I am the decorated function." decorated_function = new_decorator(decorated_function) #outputs: #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function # 呼叫被裝飾函式 decorated_function() #outputs: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. |
我們跳過中間變數,做同樣的事情
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def decorated_function(): print "I am the decorated function." decorated_function = decorator_maker()(decorated_function) #outputs: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. # 最後: decorated_function() #outputs: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. |
使用裝飾器語法,更簡短
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@decorator_maker() def decorated_function(): print "I am the decorated function." #outputs: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. #最終: decorated_function() #outputs: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. |
到這裡,我們使用@呼叫一個函式
回到問題,向裝飾器本身傳遞引數,如果我們可以通過函式去建立裝飾器,那麼我們可以傳遞引數給這個函式,對麼?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2): print "I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2 def my_decorator(func): # 這裡能傳遞引數的能力,是閉包的特性 # 更多閉包的內容,參考 http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python print "I am the decorator. Somehow you passed me arguments:", decorator_arg1, decorator_arg2 # 不要搞混了裝飾器引數和函式引數 def wrapped(function_arg1, function_arg2) : print ("I am the wrapper around the decorated function.n" "I can access all the variablesn" "t- from the decorator: {0} {1}n" "t- from the function call: {2} {3}n" "Then I can pass them to the decorated function" .format(decorator_arg1, decorator_arg2, function_arg1, function_arg2)) return func(function_arg1, function_arg2) return wrapped return my_decorator @decorator_maker_with_arguments("Leonard", "Sheldon") def decorated_function_with_arguments(function_arg1, function_arg2): print ("I am the decorated function and only knows about my arguments: {0}" " {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments("Rajesh", "Howard") #outputs: #I make decorators! And I accept arguments: Leonard Sheldon #I am the decorator. Somehow you passed me arguments: Leonard Sheldon #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Sheldon # - from the function call: Rajesh Howard #Then I can pass them to the decorated function #I am the decorated function and only knows about my arguments: Rajesh Howard |
好了,that’s it.引數可以設定為變數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
c1 = "Penny" c2 = "Leslie" @decorator_maker_with_arguments("Leonard", c1) def decorated_function_with_arguments(function_arg1, function_arg2): print ("I am the decorated function and only knows about my arguments:" " {0} {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments(c2, "Howard") #outputs: #I make decorators! And I accept arguments: Leonard Penny #I am the decorator. Somehow you passed me arguments: Leonard Penny #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Penny # - from the function call: Leslie Howard #Then I can pass them to the decorated function #I am the decorated function and only knows about my arguments: Leslie Howard |
你可以看到,你可以使用像其它函式一樣使用這個方法向裝飾器傳遞引數.如果你願意你甚至可以使用 arg *kwargs.
但是記住,裝飾器僅在Python程式碼匯入時被呼叫一次,之後你不能動態地改變引數.當你使用”import x”,函式已經被裝飾,所以你不能改變什麼
練習:一個裝飾裝飾器的裝飾器
作為獎勵,我將展示建立可以處理任何引數的裝飾器程式碼片段. 畢竟,為了接收引數,必須使用另一個函式來建立裝飾器
讓我們來給裝飾器寫一個裝飾器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 裝飾 裝飾器 的裝飾器 (好繞.....) def decorator_with_args(decorator_to_enhance): """ 這個函式將作為裝飾器使用 它必須裝飾另一個函式 它將允許任何接收任意數量引數的裝飾器 方便你每次查詢如何實現 """ # 同樣的技巧傳遞引數 def decorator_maker(*args, **kwargs): # 建立一個只接收函式的裝飾器 # 但是這裡儲存了從建立者傳遞過來的的引數 def decorator_wrapper(func): # 我們返回原始裝飾器的結果 # 這是一個普通的函式,返回值是另一個函式 # 陷阱:裝飾器必須有這個特殊的簽名,否則不會生效 return decorator_to_enhance(func, *args, **kwargs) return decorator_wrapper return decorator_maker |
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 你建立這個函式是作為一個裝飾器,但是給它附加了一個裝飾器 # 別忘了,函式簽名是: "decorator(func, *args, **kwargs)" @decorator_with_args def decorated_decorator(func, *args, **kwargs): def wrapper(function_arg1, function_arg2): print "Decorated with", args, kwargs return func(function_arg1, function_arg2) return wrapper # 然後,使用這個裝飾器(your brand new decorated decorator) @decorated_decorator(42, 404, 1024) def decorated_function(function_arg1, function_arg2): print "Hello", function_arg1, function_arg2 decorated_function("Universe and", "everything") #outputs: #Decorated with (42, 404, 1024) {} #Hello Universe and everything # Whoooot! |
我知道,到現在你一定會有這種感覺,就像你聽一個人說“在理解遞迴之前,你必須首先了解遞迴”,但是現在,掌握這兒你有沒有覺得很棒?
裝飾器使用最佳實踐
- 這是Python2.4的新特性,所以確保你的程式碼在2.4及之上的版本執行
- 裝飾器降低了函式呼叫的效能,記住這點
- You can not un-decorate a function. There are hacks to create decorators that can be removed but nobody uses them. So once a function is decorated, it’s done. For all the code.
- 裝飾器包裝函式,所以很難debug
Python2.5解決了最後一個問題,它提供functools模組,包含functools.wraps.這個函式會將被裝飾函式的名稱,模組,文件字串拷貝給封裝函式,有趣的是,functools.wraps是一個裝飾器:-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# 除錯,列印函式的名字 def foo(): print "foo" print foo.__name__ #outputs: foo # 但當你使用裝飾器,這一切變得混亂 def bar(func): def wrapper(): print "bar" return func() return wrapper @bar def foo(): print "foo" print foo.__name__ #outputs: wrapper # "functools" 可以改變這點 import functools def bar(func): # 我們所說的 "wrapper", 封裝 "func" @functools.wraps(func) def wrapper(): print "bar" return func() return wrapper @bar def foo(): print "foo" # 得到的是原始的名稱, 而不是封裝器的名稱 print foo.__name__ #outputs: foo |
裝飾器為何那麼有用
現在的問題是,我們用裝飾器來坐什麼?看起來很酷很強大,但是如果有實踐的例子會更好.好了,有1000種可能。經典的用法是,在函式的外部,擴充套件一個函式的行為(你不需要改變這個函式),或者,為了除錯的目的(我們不修改的原因是這是臨時的),你可以使用裝飾器擴充套件一些函式,而不用在這些函式中書寫相同的函式實現一樣的功能
DRY原則,例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
def benchmark(func): """ 裝飾器列印一個函式的執行時間 """ import time def wrapper(*args, **kwargs): t = time.clock() res = func(*args, **kwargs) print func.__name__, time.clock()-t return res return wrapper def logging(func): """ 裝飾器記錄函式日誌 """ def wrapper(*args, **kwargs): res = func(*args, **kwargs) print func.__name__, args, kwargs return res return wrapper def counter(func): """ 記錄並列印一個函式的執行次數 """ def wrapper(*args, **kwargs): wrapper.count = wrapper.count + 1 res = func(*args, **kwargs) print "{0} has been used: {1}x".format(func.__name__, wrapper.count) return res wrapper.count = 0 return wrapper @counter @benchmark @logging def reverse_string(string): return str(reversed(string)) print reverse_string("Able was I ere I saw Elba") print reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!") #outputs: #reverse_string ('Able was I ere I saw Elba',) {} #wrapper 0.0 #wrapper has been used: 1x #ablE was I ere I saw elbA #reverse_string ('A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!',) {} #wrapper 0.0 #wrapper has been used: 2x #!amanaP :lanac a ,noep a ,stah eros ,raj a ,hsac ,oloR a ,tur a ,mapS ,snip ,eperc a ,)lemac a ro( niaga gab ananab a ,gat a ,nat a ,gab ananab a ,gag a ,inoracam ,elacrep ,epins ,spam ,arutaroloc a ,shajar ,soreh ,atsap ,eonac a ,nalp a ,nam A |
裝飾器意味著,你可以用正確的方法實現幾乎所有的事情,而不必重寫他們
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@counter @benchmark @logging def get_random_futurama_quote(): import httplib conn = httplib.HTTPConnection("slashdot.org:80") conn.request("HEAD", "/index.html") for key, value in conn.getresponse().getheaders(): if key.startswith("x-b") or key.startswith("x-f"): return value return "No, I'm ... doesn't!" print get_random_futurama_quote() print get_random_futurama_quote() #outputs: #get_random_futurama_quote () {} #wrapper 0.02 #wrapper has been used: 1x #The laws of science be a harsh mistress. #get_random_futurama_quote () {} #wrapper 0.01 #wrapper has been used: 2x #Curse you, merciful Poseidon! |
Python本身提供了一些裝飾器:property,staticmethod,等等,
Django使用裝飾器去管理快取和許可權. Twisted to fake inlining asynchronous functions calls.用途廣泛
EDIT: 鑑於這個回答的完美,人們希望我去回答metaclass,我這樣做了
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式