Python 裝飾器學習

Python裝飾器學習(九步入門)

 

這是在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

相關文章
相關標籤/搜索