1.認(rèn)識裝飾器
在python中,對于一個函數(shù)京革,若想在其運(yùn)行前后做點(diǎn)什么奇唤,那么裝飾器是再好不過的選擇供璧,話不多說,上代碼冻记。
#!/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!
這段代碼睡毒,初看之下,確實(shí)不是很理解冗栗,接下來一步一步分析演顾,看看裝飾器到底是怎么工作的。
2.裝飾器原理
在python中隅居,方法允許作為參數(shù)傳遞钠至,想在某個函數(shù)執(zhí)行前后加點(diǎn)料,也可以這樣簡單實(shí)現(xiàn)胎源。
#!/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
只是函數(shù)名稱万栅,它并不能被調(diào)用佑钾,若執(zhí)行hello()
,就會報(bào)TypeError: 'NoneType' object is not callable
對象不能調(diào)用錯誤烦粒,這是自然休溶,在decorator
中func()
直接將傳入的函數(shù)實(shí)例化了,有人會想扰她,那如果這樣改呢兽掰?
#!/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()
確實(shí),這樣改是可以徒役,可有沒有想過孽尽,若想在函數(shù)執(zhí)行結(jié)束后加點(diǎn)裝飾呢?這樣便行不通了廉涕,可能又有人會想泻云,若這樣改呢?
#!/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()
這樣寫看起來狐蜕,恩宠纯,怎么說呢,總有種沒有意義的感覺层释,不如直接將在外部的函數(shù)放進(jìn)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~
怎么樣,輸出的結(jié)果是不是符合要求,其實(shí)簡單來看的話廉白,可以這樣理解hello()==decorator(hello)()==wrapper()
个初,最后其實(shí)就是執(zhí)行wrapper()
函數(shù)而已,事實(shí)就是如此的簡單猴蹂,不妨來驗(yàn)證一下:
#!/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函數(shù)院溺,解決問題的同時也會出現(xiàn)新的問題,那便是代碼中本來定義的hello函數(shù)豈不是被wrapper函數(shù)覆蓋了磅轻,又該如何解決這個問題呢珍逸?這時候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的代碼谆膳,是不是代碼結(jié)構(gòu)清晰明了,只不過多了個參數(shù)
#!/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.結(jié)語
只要了解裝飾器原理漱病,不管是帶參數(shù)的裝飾器,還是裝飾器類把曼,都是小菜一碟杨帽。
若有錯誤,盡請指出祝迂。