python之裝飾器

1.認識裝飾器

在python中,對于一個函數,若想在其運行前后做點什么,那么裝飾器是再好不過的選擇,話不多說,上代碼。

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 01.py
__author__ = 'howie'
from functools import wraps
def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("%s was called" % func.__name__)
        func(*args, **kwargs)
    return wrapper
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()
outputs:
hello was called
Hello howie!

這段代碼,初看之下,確實不是很理解,接下來一步一步分析,看看裝飾器到底是怎么工作的。

2.裝飾器原理

在python中,方法允許作為參數傳遞,想在某個函數執(zhí)行前后加點料,也可以這樣簡單實現。

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-1.py
__author__ = 'howie'
def decorator(func):
    print("%s was called" % func.__name__)
    func()
def hello(name="howie"):
    print("Hello %s!" % name)
decorator(hello)

由此,上面代碼也可以這樣寫:

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-2.py
__author__ = 'howie'
def decorator(func):
    print("%s was called" % func.__name__)
    func()
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello

兩段代碼執(zhí)行后:

outputs:
hello was called
Hello howie!

表面上看來,02-2.py代碼看起來也可以很好地執(zhí)行啊,可請注意,在末尾處,hello只是函數名稱,它并不能被調用,若執(zhí)行hello(),就會報TypeError: 'NoneType' object is not callable對象不能調用錯誤,這是自然,在decoratorfunc()直接將傳入的函數實例化了,有人會想,那如果這樣改呢?

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-3.py
__author__ = 'howie'
def decorator(func):
    print("%s was called" % func.__name__)
    return func
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()

確實,這樣改是可以,可有沒有想過,若想在函數執(zhí)行結束后加點裝飾呢?這樣便行不通了,可能又有人會想,若這樣改呢?

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-4.py
__author__ = 'howie'
def decorator(func):
    print("%s was called" % func.__name__)
    func()
    return bye
def bye():
    print("bye~")
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()

這樣寫看起來,恩,怎么說呢,總有種沒有意義的感覺,不如直接將在外部的函數放進decorator中,如下:

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-5.py
__author__ = 'howie'
def decorator(func):
    def wrapper():
      print("%s was called" % func.__name__)
      func()
      print("bye~")
    return wrapper
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()

執(zhí)行:

outputs:
hello was called
Hello howie!
bye~

怎么樣,輸出的結果是不是符合要求,其實簡單來看的話,可以這樣理解hello()==decorator(hello)()==wrapper(),最后其實就是執(zhí)行wrapper()函數而已,事實就是如此的簡單,不妨來驗證一下:

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-6.py
__author__ = 'howie'
def decorator(func):
    def wrapper():
      print("%s was called" % func.__name__)
      func()
      print("bye~")
    return wrapper
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()
print(hello.__name__)
outputs:
hello was called
Hello howie!
bye~
wrapper

果然就是執(zhí)行了wrapper函數,解決問題的同時也會出現新的問題,那便是代碼中本來定義的hello函數豈不是被wrapper函數覆蓋了,又該如何解決這個問題呢?這時候functions.wraps就可以登場了,代碼如下:

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 02-7.py
__author__ = 'howie'
from functools import wraps
def decorator(func):
    @wraps(func)
    def wrapper():
      print("%s was called" % func.__name__)
      func()
      print("bye~")
    return wrapper
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello()
print(hello.__name__)

執(zhí)行代碼:

outputs:
hello was called
Hello howie!
bye~
hello

functions.wraps作用是不是一目了然哈到了這一步,再看01.py的代碼,是不是代碼結構清晰明了,只不過多了個參數

#!/usr/bin/env
# -*-coding:utf-8-*-
# script: 01.py
__author__ = 'howie'
from functools import wraps
def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("%s was called" % func.__name__)
        func(*args, **kwargs)
    return wrapper
@decorator
def hello(name="howie"):
    print("Hello %s!" % name)
hello('world')

猜都猜得到執(zhí)行后輸出什么了。

3.結語

只要了解裝飾器原理,不管是帶參數的裝飾器,還是裝飾器類,都是小菜一碟。
若有錯誤,盡請指出。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 前言 Python的修飾器的英文名叫Decorator,當你看到這個英文名的時候,你可能會把其跟Design Pa...
    linheimx閱讀 664評論 0 4
  • Python之裝飾器 裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功...
    ikaroskun閱讀 398評論 0 0
  • 裝飾器的作用: 裝飾模式有很多經典的使用場景,例如插入日志、性能測試、事務處理等等,有了裝飾器,就可以提取大量函數...
    冰西瓜大郎閱讀 250評論 0 0
  • 參考網址> http://www.cnblogs.com/rhcad/archive/2011/12/21/229...
    Alecyrus閱讀 460評論 0 2
  • 像只樹袋熊閱讀 191評論 0 0

友情鏈接更多精彩內容