2013-05-03 134 views
1

我嘗試從某些OpenSource GitHub項目中瞭解以下代碼。有一個課程沒有__init__,但有一個__new__方法。該代碼給出:__new__和屬性

class Node(object): 
    #pylint: disable=W0404 

    #Singleton-Pattern 
    _instances = dict() 

    def __new__(cls, name=None): 
     """ Instanciates a node from a file, and (name=None) creates a new node 
      Caution: Filenames are always given relative to the root-dir 
      When no name is given, a new node is created. """ 

     if(name!=None and cls._instances.has_key(name)): 
      return(cls._instances[name]) 

     if(name==None): # a new node, lets find a name 
      for i in itertools.count(0): 
       name = "node%.4d"%i 
       if(cls._instances.has_key(name)): continue# new nodes might not been saved, yet 
       if(path.exists("./nodes/"+name)): continue 
       break 


     self = object.__new__(cls) 
     cls._instances[name] = self 

     #actuall init-code 
     from ZIBMolPy.pool import Pool #avoids circular imports 
     self._pool = Pool() #Pool is a singleton 
     self._name = name 
     self._tmp = Store() #for thing that need to be stored temporarly 
     self._obs = Store() 
     self.parent = None 

     if(path.exists(self.dir)): 
      self.reload() 

     #self.pool.append(self) #register with pool 
     return(self) 

    #--------------------------------------------------------------------------- 
    @property 
    def obs(self): 
     return(self._obs) 

我發現一個討論beween的__init__方法和Python's use of __new__ and __init__?__new__方法根據收視率最高的評論,如果一個人繼承一個不可變的類型像str一個只應使用新的, int,unicodetuple。但我認爲這是因爲其他原因。進一步,我不明白爲什麼類cls應該有一個名字(以及爲什麼它應該有一些文件夾任何待辦事項),爲什麼我可以叫

n= Node() 
n.obs 

的功能等OBS將是一個性質的功能,但它其實不是..

我很困惑。如果你不是,我不能等待你的迴應。

回答

3

本課使用__new__來實現單例模式。

__new__產生一個類的新實例,但在這種情況下,如果之前使用了相同的名稱,它將返回一個現有的實例。你不能用__init__來做到這一點,因爲在已經創建實例之後,這被稱爲。請注意,當cls._instances.has_key(name)False時,將調用self = object.__new__(cls)來創建該類的新實例,然後將其初始化並返回。

爲什麼類在./nodes/目錄中檢查現有路徑不清楚,這是一個特定於應用程序的檢查,如果沒有進一步的上下文,不容易再暴露。

@property修飾器用python descriptor代替函數。從類中查找屬性時,如果屬性有一個屬性,則Python將其稱爲__get__方法。 Python表達式n.obs被Python翻譯爲type(n).obs.__get__(n, type(n))。 A property對象調用封裝的函數,並在調用__get__時返回結果。

+0

謝謝你的回覆。 所以使用'__new__'的唯一原因是因爲有時候我想要一個已經被創建好的對象?這只是在'if(name!= None和cls._instances.has_key(name))'的情況下。我應該如何用name!= None調用'__new__'函數?我的意思是超時我創建了一個節點對象,我稱之爲'node = Node()',然後默認'name = None'。我還認爲cls是一個靜態的全局類對象。因此,如果我向全局類cls添加一個名稱,因爲每個對象都包含該名稱,因爲每個對象都是cls的子類 - 是否正確? – Adam 2013-05-03 17:18:58

+0

@Adam:參見['__new__'](http://docs.python.org/2/reference/datamodel.html#object.__new__)文檔; 'cls'是對'__new__'方法傳入的類對象的引用(就像'self'傳入引用當前實例的方法一樣)。 Node()爲你創建一個新名字,如果你不通過('name = None'),理論上這個項目可以在需要的時候傳入一個明確的'name'。在這種情況下,'cls'會引用'Node'類或'Node'的任何子類。 – 2013-05-03 17:22:59

+0

@Adam:Python類對象通常(在Python 3中,* always *),從'object'繼承,而不是'cls'。 'cls'只是這個方法的本地名稱。 – 2013-05-03 17:23:50