title: How can I memoize a class instantiation in Python?
body: <p>Ok, here is the real world scenario: I'm writing an application, and I have a class that represents a certain type of files (in my case this is photographs but that detail is irrelevant to the problem). Each instance of the Photograph class should be unique to the photo's filename.</p>
  
  <p>The problem is, when a user tells my application to load a file, I need to be able to identify when files are already loaded, and use the existing instance for that filename, rather than create duplicate instances on the same filename.</p>
  
  <p>To me this seems like a good situation to use memoization, and there's a lot of examples of that out there, but in this case I'm not just memoizing an ordinary function, I need to be memoizing <code>__init__()</code>. This poses a problem, because by the time <code>__init__()</code> gets called it's already too late as there's a new instance created already.</p>
  
  <p>In my research I found Python's <code>__new__()</code> method, and I was actually able to write a working trivial example, but it fell apart when I tried to use it on my real-world objects, and I'm not sure why (the only thing I can think of is that my real world objects were subclasses of other objects that I can't really control, and so there were some incompatibilities with this approach). This is what I had:</p>
  
  <pre><code>class Flub(object):
      instances = {}
  
      def __new__(cls, flubid):
          try:
              self = Flub.instances[flubid]
          except KeyError:
              self = Flub.instances[flubid] = super(Flub, cls).__new__(cls)
              print 'making a new one!'
              self.flubid = flubid
          print id(self)
          return self
  
      @staticmethod
      def destroy_all():
          for flub in Flub.instances.values():
              print 'killing', flub
  
  
  a = Flub('foo')
  b = Flub('foo')
  c = Flub('bar')
  
  print a
  print b
  print c
  print a is b, b is c
  
  Flub.destroy_all()
  </code></pre>
  
  <p>Which output this:</p>
  
  <pre><code>making a new one!
  139958663753808
  139958663753808
  making a new one!
  139958663753872
  &lt;__main__.Flub object at 0x7f4aaa6fb050&gt;
  &lt;__main__.Flub object at 0x7f4aaa6fb050&gt;
  &lt;__main__.Flub object at 0x7f4aaa6fb090&gt;
  True False
  killing &lt;__main__.Flub object at 0x7f4aaa6fb050&gt;
  killing &lt;__main__.Flub object at 0x7f4aaa6fb090&gt;
  </code></pre>
  
  <p>It's perfect! Only two instances were made for the two unique id's given, and Flub.instances clearly only has two listed.</p>
  
  <p>But when I tried to take this approach with the objects I was using, I got all kinds of nonsensical errors about how <code>__init__()</code> took only 0 arguments, not 2. So I'd change some things around and then it would tell me that <code>__init__()</code> needed an argument. Totally bizarre.</p>
  
  <p>After a while of fighting with it, I basically just gave up and moved all the <code>__new__()</code> black magic into a staticmethod called <code>get</code>, such that I could call <code>Photograph.get(filename)</code> and it would only call <code>Photograph(filename)</code> if filename wasn't already in <code>Photograph.instances</code>.</p>
  
  <p>Does anybody know where I went wrong here? Is there some better way to do this?</p>
  
  <p>Another way of thinking about it is that it's similar to a singleton, except it's not globally singleton, just singleton-per-filename.</p>
  
  <p><a href="https://github.com/robru/gottengeography/blob/908a1842116dc26ca57e3e4db6802fa563bc2008/gg/photos.py#L74">Here's my real-world code using the staticmethod get</a> if you want to see it all together.</p>