這是在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 )) |
下面是參考資料,當初有不少地方沒看明白,真正練習後才明白些:
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