2015-11-22 61 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__'更安全。 –