python面對對象編程----------7:callable(類調用)與context(上下文)

一:callablespython

  callables使類實例可以像函數同樣被調用
  若是類須要一個函數型接口這時用callable,最好繼承自abc.Callable,這樣有些檢查機制而且一看就知道此類的目的是callable對象
若是類須要有‘記憶’功能,使用callable是很是方便的相對於函數而言,callable語法什麼的就要複雜多了,這也是其主要的缺點:
    def x(args):
body
轉化爲callable對象:
class X(collections.abc.callable):
def __call__(self, args):
body
x= X()


  1:計算x^y
 1 import collections.abc                          #注,徹底能夠不引入cleection.abc,引入是爲了可以作一些錯誤檢查
 2     class Power1( collections.abc.Callable ):
 3     def __call__( self, x, n ):
 4         p= 1
 5         for i in range(n):
 6             p *= x
 7         return p
 8 
 9 power= Power1()
10 >>> power( 2, 0 )           #像函數同樣調用實例
11 1
12 >>> power( 2, 1 )
13 2
14 >>> power( 2, 2 )
15 4
16 >>> power( 2, 10 )
17 1024
18 
19 # 提高性能:上面是O(n),用遞歸改進爲O(logn)
20 class Power4( abc.Callable ):
21     def __call__( self, x, n ):
22         if n == 0:
23             return 1
24         elif n % 2 == 1:
25             return self.__call__(x, n-1)*x
26         else:
27             t= self.__call__(x, n//2)
28             return t*t
29 
30 pow4= Power4()
31 
32 # 再次提高性能,使用記憶功能【注:能夠{(2,4):16,... }
33 class Power5( collections.abc.Callable ):
34     def __init__( self ):
35         self.memo = {}
36     def __call__( self, x, n ):
37         if (x,n) not in self.memo:
38             if n == 0:
39                 self.memo[x,n]= 1
40             elif n % 2 == 1:
41                 self.memo[x,n]= self.__call__(x, n-1) * x
42             elif n % 2 == 0:
43                 t= self.__call__(x, n//2)
44                 self.memo[x,n]= t*t
45             else:
46                 raise Exception("Logic Error")
47         return self.memo[x,n]
48 
49 pow5= Power5()
50 
51 # 再次改進,python庫自帶了一個記憶裝飾器,可使用這個從而不不用自定義callable對象
52 from functools import lru_cache
53 @lru_cache(None)
54 def pow6( x, n ):
55     if n == 0:
56         return 1
57     elif n % 2 == 1:
58         return pow6(x, n-1)*x
59     else:
60         t= pow6(x, n//2)
61         return t*t
62 # Previous requests are stored in a memoization cache. The requests are
63 # tracked in the cache, and the size is limited. The idea behind an LRU cache is that
64 # the most recently made requests are kept and the least recently made requests are quietly purged.
callable試例1

   2:賭注翻倍:綜合運用callables,輸家翻倍賭注政策:每輸一次後賭注就加倍直到贏了後迴歸本來賭注ide

 1 class BettingMartingale( BettingStrategy ):
 2     def __init__( self ):
 3         self._win= 0
 4         self._loss= 0
 5         self.stage= 1
 6     @property
 7     def win(self):
 8         return self._win
 9     @win.setter
10     def win(self, value):
11         self._win = value
12         self.stage= 1
13     @property
14     def loss(self):
15         return self._loss
16     @loss.setter
17     def loss(self, value):
18         self._loss = value
19         self.stage *= 2
20 
21     def __call__( self ):
22         return self.stage
23 
24 >>> bet= BettingMartingale()
25 >>> bet()
26 1
27 >>> bet.win += 1
28 >>> bet()
29 1
30 >>> bet.loss += 1
31 >>> bet()
32 2
33 
34 # property的使用使類的定義顯得冗雜,實際上咱們只關心setters,因此咱們用__setattr__來改進上述版本
35 class BettingMartingale2( BettingStrategy ):
36     def __init__( self ):
37         self.win= 0
38         self.loss= 0
39         self.stage= 1
40     def __setattr__( self, name, value ):
41         if name == 'win':
42             self.stage = 1
43         elif name == 'loss':
44             self.stage *= 2
45         super().__setattr__( name, value )
46     def __call__( self ):
47         return self.stage
callable示例2

 


二:context
  A context is generally used to acquire/release, open/close, and lock/unlock types of operation pairs.
  Most of the examples are file I/O related, and most of the file-like objects in Python are already proper context managers.
  1:一些context
   1:最多見的是用在文件的,with語句建立
   2:decimal context:decimal是一個模塊,經常使用於一些對於精度要求比較嚴格的計算,其自己運行在一個context中,經過改context能夠對全局的計算產生影響
   3:還有一些context,主要都是用於類文件的操做
  2:構造context(第八章會詳細講解構造context)
   context最主要的是有__enter__()與__exit__()方法,分別在with語句開始和結束時調用
   拋出的問題都會以traceback參數傳遞到__exit__()函數中,應該作相應處理。

  例子:錯誤處理context:在打開文件時作備份,若處理完文件沒出問題就刪除備份,若出了問題就使用備份來恢復原文件
 1 import os
 2 class Updating:
 3     def __init__( self, filename ):
 4         self.filename= filename
 5     def __enter__( self ):                  #作文件備份
 6         try:
 7             self.previous= self.filename+" copy"
 8             os.rename( self.filename, self.previous )
 9         except FileNotFoundError:
10             # Never existed, no previous copy
11             self.previous= None
12 
13     def __exit__( self, exc_type, exc_value, traceback ):       #
14         if exc_type is not None:
15             try:
16                 os.rename( self.filename, self.filename+ " error" )
17             except FileNotFoundError:
18                 pass # Never even got created?
19             if self.previous:
20                 os.rename( self.previous, self.filename )       #用備份文件恢復原文件
21 
22 with Updating( "some_file" ):
23     with open( "some_file", "w" ) as target:
24          process( target )
相關文章
相關標籤/搜索