title: Python decorator get or set dictionary value in class
body: <p>I'm working on a class representing on object with numerous associated data. I'm storing these data in a dictionary class attribute called <em>metadata</em>. A representation could be:</p>
  
  <pre><code>{'key1':slowToComputeValue, 'key2':evenSlowerToComputeValue}
  </code></pre>
  
  <p>The calculating of the values is in some cases <strong>very</strong> slow, so what I want to do is, using "getter" functions, first try and get the value from the <em>metadata</em>  dict. Only on a KeyError (i.e. when the getter tries to get a value for a key which doesn't exist yet) should the value be calculated (and added to the dictionary for fast access next time the getter is called).</p>
  
  <p>I began with a simple:</p>
  
  <pre><code>try:
      return self.metadata[requested_key]
  except KeyError:
      #Implementation of function
  </code></pre>
  
  <p>As there are many getters in the class, I started thought that these first 3 lines of code could be handled by a decorator. However I'm having problems making this work. The problem is that I need to pass the metadata dictionary from the class instance to the decorator. I've found several tutorials and posts like <a href="https://stackoverflow.com/questions/10176226/how-to-pass-extra-arguments-to-python-decorator">this</a> one which show that it is possible to send a parameter to an enclosing function but the difficulty I'm having is sending a class instantiation attribute metadata to it (if I send a string value it works).</p>
  
  <p>Some example code from my attempt is here:</p>
  
  <pre><code>def get_existing_value_from_metadata_if_exists(metadata):
      def decorator(function):
          @wraps(function)
          def decorated(*args, **kwargs):
              function_name = function.__name__
              if function_name in metadata.keys():
                  return metadata[function_name]
              else:
                  function(*args, **kwargs)
          return decorated
      return decorator
  
  class my_class():
      @get_existing_value_from_metadata_if_exists(metadata)
      def get_key1(self):
          #Costly value calculation and add to metadata
  
      @get_existing_value_from_metadata_if_exists(metadata)
      def get_key2(self):
          #Costly value calculation and add to metadata
  
      def __init__(self):
          self.metadata = {}
  </code></pre>
  
  <p>The errors I'm getting are generally self not defined but I've tried various combinations of parameter placement, decorator placement etc. without success.</p>
  
  <p>So my questions are:</p>
  
  <ol>
  <li>How can I make this work?</li>
  <li>Are decorators a suitable way to achieve what I'm trying to do?</li>
  </ol>