2

Is it OK to have 2 constructor functions, the regular __init__ and a @classmethod Animal.get?

Since creating a new object is computationally intensive, we want to store previously created instances in a class attribute cls.zoo and get a cached copy of the instance from cls.zoo if it exists.

The user will not access Animal.zoo directly. If the user wants to get an Animal object, he will always use Animal.get().

Is this approach proper/pythonic?

I'm not familiar with the Singleton Pattern. Is the code considered using the Singleton Pattern?

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')
Nyxynyx
  • 61,411
  • 155
  • 482
  • 830

1 Answers1

3

It depends whether you just want to allow the user of your class to access a cached object, or if you want to force it to only access that cached object. With you solution, user can always use tiger2 = Animal('tiger', 0) to get another instance.

If you really want only one instance, you can use __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

Here is the proof that you can only create one instance:

>>> tiger1 = Animals('tiger')
EXPENSIVE CALLED
>>> tiger2 = Animals('tiger')
>>> tiger2 is tiger1
True
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • The user is forced to use the cache object if it is available. In this case, how will you decide when to use `__new__` vs. the `classmethod`? – Nyxynyx Nov 25 '15 at 02:16
  • @Nyxynyx : with the class method, the user can always create a new object without using it. The `__new__` method is called for each new instance. So if you want to always use the cache, `__new__` is more secure. – Serge Ballesta Nov 25 '15 at 06:44