由於沒有真正實用經驗,所以只記錄基本用法,以免經常不用忘的太徹底。
簡單說,decorator也是一個函數,可以在不更改另一個函數的情況下,改變或增加另一個函數的功能。
1,不使用裝飾器。
def decoTest(func):
print("before")
func()
print("after")
def test():
print('Hello, World')
decoTest(test)
爲了達到在test()執行前後分別執行不同語句功能,將test作爲參數,傳入decoTest中。之後需要調用decoTest函數,如果想直接調用test來達到這個目的,需要使用裝飾器。
2,使用@語法
def decoTest(func):
print("before")
func()
print("after")
return func
@decoTest
def test():
print('Hello, World')
test
在decoTest中增加了返回值,返回傳入的函數。相當於執行了decoTest(test)。所以結果與上面的相同。所以如果最後調用的是test(),將多輸出一個Hello, World。
3,爲解決2中調用test()多輸出一個Hello, World。對decoTest進行包裝,使它返回一個函數。
def decoTest(func):
def wrapper():
print('before')
func()
print('after')
return wrapper
@decoTest
def test():
print('Hello, World')
test()
此時的輸出不會再多一行。因爲返回的是函數,執行test()相當是將test傳入decoTest中,decoTest返回wrapper,此時因爲執行的是test(),所以最終會執行wrapper()。
4,解決帶參數函數的裝飾。
def decoTest(func):
def wrapper(a, b):
print('before')
func(a, b)
print('after')
return wrapper
@decoTest
def test(a, b):
print('a + b =', a + b)
test(2, 9)
結果爲:
before a + b = 11 after
因爲裝飾器函數返回的是一個函數,所以可以接受參數。所以2,9也傳入了wrapper中,所以返回正確。
5,使用*, **來解決參數數量的不確定性。
def decoTest(func):
def wrapper(*args, **kwargs):
print('before')
func(*args, **kwargs)
print('after')
return wrapper
@decoTest
def test(a, b, c, d):
print('sum =', a + b + c + d)
@decoTest
def test2(*args, **kwargs):
print("%s, %s" % (args, kwargs))
test(2, 9, 10, 23)
test2(2, 3, 5, a = 5, c = 2)
test和test2都實現了在本身函數之前之後分別輸出某個語句。
6,裝飾器函數也可以傳入參數。
def deco(arg) :
def decoTest(func):
def wrapper(*args, **kwargs):
print('before', arg)
func(*args, **kwargs)
print('after', arg)
return wrapper
return decoTest
@deco("test")
def test(a, b, c, d):
print('sum =', a + b + c + d)
@deco("test2")
def test2(*args, **kwargs):
print("%s, %s" % (args, kwargs))
test(2, 9, 10, 23)
test2(2, 3, 5, a = 5, c = 2)
輸出結果爲:
before test
sum = 44
after test
before test2
(2, 3, 5), {'c': 2, 'a': 5}
after test2
裝飾器函數裏面嵌套定義了兩個函數。例子中裝飾器函數爲deco,deco返回的是函數decoTest,decoTest有一個函數參數,裝飾器返回的函數可以接受另一個函數,而decoTest又返回了wrapper函數。所以decoTest函數可以接受多個參數並最終輸出。