這是在Python學習小組上介紹的內容,現學現賣、多練習是好的學習方式。html
第一步:最簡單的函數,準備附加額外功能編程
1
2
3
4
5
6
7
8
|
# -*- coding:gbk -*-
'''示例1: 最簡單的函數,表示調用了兩次'''
def
myfunc():
print
(
"myfunc() called."
)
myfunc()
myfunc()
|
第二步:使用裝飾函數在函數執行前和執行後分別附加額外功能app
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()
|
第四步:使用內嵌包裝函數來確保每次新函數都被調用post
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
)
|
第六步:對參數數量不肯定的函數進行裝飾ui
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
)
|
第七步:讓裝飾器帶參數url
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()
|
第八步:讓裝飾器帶 類 參數spa
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文件中,同時演示了對一個函數應用多個裝飾器.net
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
))
|
下面是參考資料,當初有很多地方沒看明白,真正練習後才明白些:
1. Python裝飾器學習 http://blog.csdn.net/thy38/article/details/4471421
2. Python裝飾器與面向切面編程http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html
3. Python裝飾器的理解 http://apps.hi.baidu.com/share/detail/17572338