title: Creating a huge lookup table, issues on performance
body: <p>I would like to create a lookup table, and for that I am thinking of using a dictionary. The dictionary would have keys corresponding to an integer (or in my case to an enumerated type from the class <code>Enum</code>), and the values would be 2, 3 or 4 numpy arrays. But somehow I'm reluctant to use this approach as this dictionary has a huge amount of information, and 99% of it may not be used at all for some problems. So then it doesn't make sense to build a single object containing all lookup information, and even though I'm speculating, I'm almost certain that there's a better approach to accomplish what I want to do.</p>
  
  <p>So coming from a C++ world, I would create a <code>unordered_map</code> of enum types to function pointers, where in the function I would create a <code>static</code> array (so that it would be created only once) and then I would return the array pointer. In this way I would only instantiate the part of the lookup table that's really needed for the program instead of the whole thing.</p>
  
  <p>But I'm trying to do something similar in Python, so I would like to know what's the most efficient way to accomplish this.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>So this is what I came up with so far. I kind of mixed the suggestions made by @AaronDigulla and @DanielRoseman, even though the <code>@runonce</code> may not be necessary anymore. A subclass of <code>dict</code> overrides the <code>__getitem__</code> method and checks if a key exists in the dictionary. If it doesn't, it calls a function (using <code>eval()</code> on a concatenated string from the dictionary key values). I would appreciate any improvements to the given code. It looks quite complex but it works, so I'm wondering if it can be simplified further.</p>
  
  <pre><code>import collections, types
  import numpy as np
  
  Quadrature = collections.namedtuple("Quadrature", "wgt xi eta zeta")
  
  category_map = { "t3" : "tri" #... more types
                 }
  
  
  class Integrator(dict):
  
    def __init__(self, *args, **kwargs):
      self.update(*args, **kwargs)
  
    def __getitem__(self, key):
  
      if not key in self:
  
        fn = '{}_{}gp'.format(category_map[key[0]], str(key[1]))
        super().__setitem__(key, eval(fn)())
  
      val = super().__getitem__(key)
      return val
  
    def __repr__(self):
      dictrepr = dict.__repr__(self)
      return '%s(%s)' % (type(self).__name__, dictrepr)
  
    def update(self, *args, **kwargs):
      print ('update', args, kwargs)
      for k, v in dict(*args, **kwargs).items():
          self[k] = v
  
  def run_once(f):
    def wrapper(*args, **kwargs):
      if not wrapper.has_run:
        wrapper.has_run = True
        return f(*args, **kwargs)
    wrapper.has_run = False
    return wrapper
  
  
  @run_once
  def tri_3gp():
    xi   = np.array([2/3., 1/6., 1/6.])
    eta  = np.array([1/6., 1/6., 2/3.])
    wgt  = np.array([2/3., 2/3., 2/3.]);
    return Quadrature(wgt, xi, eta, None)
  </code></pre>