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 Enum
), 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.
So coming from a C++ world, I would create a unordered_map
of enum types to function pointers, where in the function I would create a static
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.
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.
EDIT
So this is what I came up with so far. I kind of mixed the suggestions made by @AaronDigulla and @DanielRoseman, even though the @runonce
may not be necessary anymore. A subclass of dict
overrides the __getitem__
method and checks if a key exists in the dictionary. If it doesn't, it calls a function (using eval()
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.
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)