2015-11-22 105 views
2

可以有2個構造函數,常規的__init__@classmethodAnimal.getPython類中的兩個構造函數

由於創建新對象的計算量很大,我們希望將先前創建的實例存儲在類屬性cls.zoo中,如果存在,則從cls.zoo獲取實例的緩存副本。用戶不會直接訪問Animal.zoo。如果用戶想要獲得Animal對象,他總是會使用Animal.get()

這種方法是正確的/ pythonic?

我不熟悉Singleton模式。代碼是否考慮使用Singleton模式?

class Animal: 

    zoo = {} 

    # will not be called directly from outside the class 
    def __init__(self, species ,age): 
     self.species = species 
     self.age = age 
     self.runExpensiveFunction() 

    # User alway use this function 
    @classmethod 
    def get(cls, species): 
     if species in cls.zoo: 
      animal = cls.zoo[species] 
     else: 
      animal = Animal(species, 0) 
      cls.zoo[species] = animal 

     return animal 

tiger = Animal.get('tiger') 
bear = Animal.get('bear') 
+0

如果這是你認爲工作代碼可以改進,考慮[codereview.se](雖然他們會想要實際的代碼,而不是一個虛擬的例子)。 – jonrsharpe

+1

這是真實的代碼嗎?看起來它可能是演示/播放代碼,這對Code Review來說是無關緊要的。 – Phrancis

+0

相反,通過類方法的替代構造函數沒有什麼問題。 – MaxNoe

回答

3

這取決於你是否只想讓你的類的用戶訪問緩存的對象,或者如果你想用它強制只緩存的對象訪問。有了你的解決方案,用戶總是可以使用tiger2 = Animal('tiger', 0)來獲得另一個實例。

如果你真的想只有一個實例,您可以使用__new__

class Animals(object): 
    zoo = {} 
    def runExpensiveFunction(self): 
     print "EXPENSIVE CALLED" 
    def __new__(cls, species): 
     if species in cls.zoo: 
      return cls.zoo[species] 
     else: 
      animal = object.__new__(Animals) 
      animal.species = species 
      animal.age = 0 
      animal.runExpensiveFunction() 
      Animals.zoo[species] = animal 
      return animal 

這裏,你只能創建一個實例證明:

>>> tiger1 = Animals('tiger') 
EXPENSIVE CALLED 
>>> tiger2 = Animals('tiger') 
>>> tiger2 is tiger1 
True 
+0

用戶被強制使用緩存對象(如果可用)。在這種情況下,你將如何決定何時使用'__new__'與'classmethod'? – Nyxynyx

+0

@Nyxynyx:使用類方法,用戶可以始終創建一個新對象而不使用它。爲每個新實例調用'__new__'方法。所以如果你想總是使用緩存,'__new__'更安全。 –