今天看了一些函數裝飾器的知識,第一遍沒看懂,後來才一點點弄明白。。。html
首先,函數也是對象,因此能夠返回函數函數
def hello(func): #func是函數名學習
def h():#在函數內部的函數ui
print 'hello world'spa
func().net
return hcode
@hello htm
def d():對象
print 'charles dong !'blog
d()
輸出:
‘hello world’
‘charles dong’
裝飾器也能夠有參數
def
deco(arg):#arg='mymodule'
def
_deco(func):#func=myfunc()
def
__deco():
print
(
"before %s called [%s]."
%
(func.__name__, arg))
func()
print
(
" after %s called [%s]."
%
(func.__name__, arg))
return
__deco
return
_deco
def
myfunc():
print
(
" myfunc() called."
)
這是在Python學習小組上介紹的內容,現學現賣、多練習是好的學習方式。
第一步:最簡單的函數,準備附加額外功能
1
2
3
4
5
6
7
8
|
# -*- coding:gbk -*-
'''示例1: 最簡單的函數,表示調用了兩次'''
def
myfunc():
print
(
"myfunc() called."
)
myfunc()
myfunc()
|
第二步:使用裝飾函數在函數執行前和執行後分別附加額外功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# -*- coding:gbk -*-
'''示例2: 替換函數(裝飾)
裝飾函數的參數是被裝飾的函數對象,返回原函數對象
裝飾的實質語句: myfunc = deco(myfunc)'''
def
deco(func):
print
(
"before myfunc() called."
)
func()
print
(
" after myfunc() called."
)
return
func
def
myfunc():
print
(
" myfunc() called."
)
myfunc
=
deco(myfunc)
myfunc()
myfunc()
|
第三步:使用語法糖@來裝飾函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# -*- coding:gbk -*-
'''示例3: 使用語法糖@來裝飾函數,至關於「myfunc = deco(myfunc)」
但發現新函數只在第一次被調用,且原函數多調用了一次'''
def
deco(func):
print
(
"before myfunc() called."
)
func()
print
(
" after myfunc() called."
)
return
func
@deco
def
myfunc():
print
(
" myfunc() called."
)
myfunc()
myfunc()
|
第四步:使用內嵌包裝函數來確保每次新函數都被調用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# -*- coding:gbk -*-
'''示例4: 使用內嵌包裝函數來確保每次新函數都被調用,
內嵌包裝函數的形參和返回值與原函數相同,裝飾函數返回內嵌包裝函數對象'''
def
deco(func):
def
_deco():
print
(
"before myfunc() called."
)
func()
print
(
" after myfunc() called."
)
# 不須要返回func,實際上應返回原函數的返回值
return
_deco
@deco
def
myfunc():
print
(
" myfunc() called."
)
return
'ok'
myfunc()
myfunc()
|
第五步:對帶參數的函數進行裝飾
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# -*- coding:gbk -*-
'''示例5: 對帶參數的函數進行裝飾,
內嵌包裝函數的形參和返回值與原函數相同,裝飾函數返回內嵌包裝函數對象'''
def
deco(func):
def
_deco(a, b):
print
(
"before myfunc() called."
)
ret
=
func(a, b)
print
(
" after myfunc() called. result: %s"
%
ret)
return
ret
return
_deco
@deco
def
myfunc(a, b):
print
(
" myfunc(%s,%s) called."
%
(a, b))
return
a
+
b
myfunc(
1
,
2
)
myfunc(
3
,
4
)
|
第六步:對參數數量不肯定的函數進行裝飾
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
|
# -*- coding:gbk -*-
'''示例6: 對參數數量不肯定的函數進行裝飾,
參數用(*args, **kwargs),自動適應變參和命名參數'''
def
deco(func):
def
_deco(
*
args,
*
*
kwargs):
print
(
"before %s called."
%
func.__name__)
ret
=
func(
*
args,
*
*
kwargs)
print
(
" after %s called. result: %s"
%
(func.__name__, ret))
return
ret
return
_deco
@deco
def
myfunc(a, b):
print
(
" myfunc(%s,%s) called."
%
(a, b))
return
a
+
b
@deco
def
myfunc2(a, b, c):
print
(
" myfunc2(%s,%s,%s) called."
%
(a, b, c))
return
a
+
b
+
c
myfunc(
1
,
2
)
myfunc(
3
,
4
)
myfunc2(
1
,
2
,
3
)
myfunc2(
3
,
4
,
5
)
|
第七步:讓裝飾器帶參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# -*- coding:gbk -*-
'''示例7: 在示例4的基礎上,讓裝飾器帶參數,
和上一示例相比在外層多了一層包裝。
裝飾函數名實際上應更有意義些'''
def
deco(arg):
def
_deco(func):
def
__deco():
print
(
"before %s called [%s]."
%
(func.__name__, arg))
func()
print
(
" after %s called [%s]."
%
(func.__name__, arg))
return
__deco
return
_deco
@deco
(
"mymodule"
)
def
myfunc():
print
(
" myfunc() called."
)
@deco
(
"module2"
)
def
myfunc2():
print
(
" myfunc2() called."
)
myfunc()
myfunc2()
|
第八步:讓裝飾器帶 類 參數
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
|
# -*- coding:gbk -*-
'''示例8: 裝飾器帶類參數'''
class
locker:
def
__init__(
self
):
print
(
"locker.__init__() should be not called."
)
@staticmethod
def
acquire():
print
(
"locker.acquire() called.(這是靜態方法)"
)
@staticmethod
def
release():
print
(
" locker.release() called.(不須要對象實例)"
)
def
deco(
cls
):
'''cls 必須實現acquire和release靜態方法'''
def
_deco(func):
def
__deco():
print
(
"before %s called [%s]."
%
(func.__name__,
cls
))
cls
.acquire()
try
:
return
func()
finally
:
cls
.release()
return
__deco
return
_deco
@deco
(locker)
def
myfunc():
print
(
" myfunc() called."
)
myfunc()
myfunc()
|
第九步:裝飾器帶類參數,並分拆公共類到其餘py文件中,同時演示了對一個函數應用多個裝飾器
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
|
# -*- coding:gbk -*-
'''mylocker.py: 公共類 for 示例9.py'''
class
mylocker:
def
__init__(
self
):
print
(
"mylocker.__init__() called."
)
@staticmethod
def
acquire():
print
(
"mylocker.acquire() called."
)
@staticmethod
def
unlock():
print
(
" mylocker.unlock() called."
)
class
lockerex(mylocker):
@staticmethod
def
acquire():
print
(
"lockerex.acquire() called."
)
@staticmethod
def
unlock():
print
(
" lockerex.unlock() called."
)
def
lockhelper(
cls
):
'''cls 必須實現acquire和release靜態方法'''
def
_deco(func):
def
__deco(
*
args,
*
*
kwargs):
print
(
"before %s called."
%
func.__name__)
cls
.acquire()
try
:
return
func(
*
args,
*
*
kwargs)
finally
:
cls
.unlock()
return
__deco
return
_deco
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# -*- coding:gbk -*-
'''示例9: 裝飾器帶類參數,並分拆公共類到其餘py文件中
同時演示了對一個函數應用多個裝飾器'''
from
mylocker
import
*
class
example:
@lockhelper
(mylocker)
def
myfunc(
self
):
print
(
" myfunc() called."
)
@lockhelper
(mylocker)
@lockhelper
(lockerex)
def
myfunc2(
self
, a, b):
print
(
" myfunc2() called."
)
return
a
+
b
if
__name__
=
=
"__main__"
:
a
=
example()
a.myfunc()
print
(a.myfunc())
print
(a.myfunc2(
1
,
2
))
print
(a.myfunc2(
3
,
4
))
|
實現一個裝飾器d2使下面的代碼打印相應的結果:
@d2('a', 'b')
def test(arg1, arg2):
print 'test', arg1, arg2
test('c', 'd')
[output]
before test a b
test c d
[/output]
def d2(a,b):
def dd2(func):
def ddd2(arg1,arg2):
print '[output]'
print 'befot test', a, b
test(argv1, argv2)
print '[/output]'
return ddd2
return dd2