title: Wrapping a python class around JSON data, which is better?
body: <p>
  <strong>Preamble</strong>: I'm writing a python API against a service that delivers JSON.
  The files are stored in JSON format on disk to cache the values.
  The API should sport classful access to the JSON data, so IDEs and users can have a clue what (read-only) attributes there are in the object before runtime while also providing some convenience functions.</p>
  
  <p><strong>Question</strong>: I have two possible implementations, I'd like to know which is nicer or 'pythonic'. While I like both, I am open for suggestions, if you come up with a better solution.</p>
  
  <p><strong>First Solution: defining and inheriting JSONWrapper</strong> while nice, it is pretty verbose and repetitive.</p>
  
  <pre class="lang-py prettyprint-override"><code>class JsonDataWrapper:
      def __init__(self, json_data):
          self._data = json_data
  
      def get(self, name):
          return self._data[name]
  
  
  class Course(JsonDataWrapper):
      def __init__(self, data):
          super().__init__(data)
          self._users = {}  # class omitted
          self._groups = {}  # class omitted
          self._assignments = {}
  
      @property
      def id(self): return self.get('id')
  
      @property
      def name(self): return self.get('full_name')
  
      @property
      def short_name(self): return self.get('short_name')
  
      @property
      def users(self): return self._users
  
      @users.setter
      def users(self, data):
          users = [User(u) for u in data]
          for user in users:
              self.users[user.id] = user
              # self.groups = user  # this does not make much sense without the rest of the code (It works, but that decision will be revised :D)
  </code></pre>
  
  <p><strong>Second solution: using lambda for shorter syntax.</strong> While working and short, it does not quite look right (see edit1 below.)</p>
  
  <pre class="lang-py prettyprint-override"><code>def json(name): return property(lambda self: self.get(name))
  
  class Group(JsonDataWrapper):
      def __init__(self, data):
          super().__init__(data)
          self.group_members = []  # elements are of type(User). edit1, was self.members = []
  
      id = json('id')
      description = json('description')
      name = json('name')
      description_format = json('description_format')
  </code></pre>
  
  <p>(Naming this function 'json' is not a problem, since I don't import json there.)</p>
  
  <p>I have a possible third solution in mind, that I cant quite wrap my head around: overriding the property builtin, so I can define a decorator that wraps the returned field name for lookup:</p>
  
  <pre class="lang-py prettyprint-override"><code>@json  # just like a property fget
  def short_name(self): return 'short_name'
  </code></pre>
  
  <p>That could be a little shorter, dunno if that makes code better.</p>
  
  <p><strong>Disqualified solutions</strong> (IMHO):</p>
  
  <ul>
  <li>JSON{De,En}coder: kills all flexibility, provide no means of read-only attributes</li>
  <li><code>__{get,set}attr__</code>: makes it impossible to determine attributes before runtime. While it whould shorten <code>self.get('id')</code> to <code>self['id']</code> it whould also further complicate matters where an attribute was not in the underlying json data.</li>
  </ul>
  
  <p>Thank you for reading!</p>
  
  <p><strong>Edit 1: 2016-07-20T08:26Z</strong> </p>
  
  <p>To further clarify (@SuperSaiyan) why I don't quite like the second solution:
  I feel the lambda function is completely disconnected from the rest of classes semantics (which is also the reason why it is shorter :D). I think I can help myself liking it more by properly documenting the decision in the code. The first solution is easy to understand for everybody who understands the meaning of <code>@property</code> without any additional explaination.</p>
  
  <p>On the second comment of @SuperSaiyan: Your question is, why I put <code>Group.members</code> as attribute in there? The list stores type(User) entities, might not be what you think it is, I changed the example.</p>
  
  <p>@jwodder: I will use Code Review next time, did not know that was a thing.</p>
  
  <p>(Also: I really think the <code>Group.members</code> threw some of you off, I edited the code to make it a little more obvious: Group members are Users that will be added to the list.</p>
  
  <p><a href="https://github.com/manly-man/moodle-destroyer-tools/blob/7b60b57122b9eacc7d77d21debea89668c53487c/moodle/models.py" rel="nofollow">The complete code is on github</a>, while undocumented it may be interesting for somebody. Keep in mind: this is all WIP :D)</p>