2011-09-14 81 views
0

我希望能夠在對象實例化過程中動態加載實例方法。根據我的設計,默認行爲是在基類中編碼的。然而,如果 某些條件在對象instatination期間得到滿足,我動態0​​用另一段代碼改變這種行爲。這是我 做到這一點:在對象實例化過程中動態加載實例方法

的默認行爲是在編碼first.py

class First(object): 
    def __init__(self, p): 
     p = str(p) 
     #The decision whether or not to perform default action is done 
     #in the following try/except block. In reality this block 
     #is more complicated 
     #and more checks are performed in order to assure proper work 
     try: 
      strImport = "__import__('module%s')"%p 
      e = eval(strImport, {}, {}) 
      if not hasattr(e, p): 
       raise ImportError() 
     except ImportError: 
      e = None #default behaviour 
     if e is not None: 
      self.act = getattr(e, p)(p).act #special behaviour 
     self.p = p 

    def act(self): 
     print 'Default behaviour' 


import cPickle as pickle 



if __name__ == '__main__': 
    print 'first' 
    first = First('f') 
    first.act() 
    pickle.dump(first, open('first.dump', 'w')) 

    print 'third' 
    third = First('Third') 
    third.act() 
    pickle.dump(third, open('third.dump', 'w')) 

在上面的代碼,都firstthird進行默認操作。我可以通過將文件moduleThird.py如下改變third的 行爲:該文件已經被添加

from temp import First 
class Third(First): 
    def __init__(self, p): 
     p = 'Third *** %p' 
     print 'third init' 
     super(self.__class__, self).__init__(p) 


    def act(self): 
     super(self.__class__, self).act() 
     print 'Third acted' 

後,third改變其行爲。但是我不 無法酸洗產生的目標由於以下錯誤:

Traceback (most recent call last): 
    File "C:\temp\temp.py", line 35, in <module> 
    pickle.dump(fff, open('fff.dump', 'w')) 
    File "C:\Python26\lib\copy_reg.py", line 70, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle instancemethod objects 

很明顯的是,動態加載方法Third.act導致與泡菜的問題。我如何需要改變我的方法以獲得可選對象(以及更優雅的代碼)?

有沒有更好的方法來實現我的目標?

+0

看看「如何判斷對哪個對象屬性泡菜失敗?」在這個網站上。 Interresting幫助課有一個答案,可以告訴哪個部分不能被醃製。 – Louis

+0

@Louis,我知道哪種方法會導致醃汁問題(請參閱我在問題結尾添加的內容)。我正在尋找解決這些問題的方法。 –

回答

1

如果你改變你的代碼,然後遵守它應該工作:

class First(object): 
    def __init__(self, p): 
     p = str(p) 
     #The decision whether or not to perform default action is done 
     #in the following try/except block. In reality this block 
     #is more complicated 
     #and more checks are performed in order to assure proper work 
     try: 
      strImport = "__import__('module%s')"%p 
      print strImport 
      e = eval(strImport, {}, {}) 
      if not hasattr(e, p): 
       raise ImportError() 

      self.override_obj = getattr(e, p)(p) 
     except ImportError: 
      e = None #default behaviour 
      self.override_obj = None 

     self.p = p 

    def act(self): 
     if self.override_obj: 
      return self.override_obj.act() 
     else: 
      print 'Default behaviour' 
+0

換句話說,保持對實例的引用,而不是實例方法。然後在需要時調用該方法。 –

+0

是的,這絕對有效,但這樣我們最終得到兩個幾乎相同的對象的副本... –

+0

如果你想讓它們在概念上不同,那麼你可以嘗試一個工廠函數而不是實例化First。這個函數可以嘗試導入,然後返回一個合適的實例。 –