title: object_hook in json module doesn't seem to work as I'd expect
body: <p>I'm having trouble understanding how the object_hook functionality from json.loads() actually works.  I found a similar question <a href="https://stackoverflow.com/questions/38234765/object-hook-does-not-address-the-full-json">object_hook does not address the full json</a> here, but I've tried to follow what I understand from it, and it's still not working for me.  I already gathered that the object_hook function is called recursively in some way, but I'm failing to understand how to use it to construct complex object hierarchies from the json string.  Consider the following json string, classes, and object_hook function:</p>
  
  <pre><code>import json
  from pprint import pprint
  
  jstr = '{"person":{ "name": "John Doe", "age": "46", \
             "address": {"street": "4 Yawkey Way", "city": "Boston", "state": "MA"} } }'
  
  class Address:
      def __init__(self, street=None, city=None, state=None):
          self.street = street
          self.city = city
          self.state = state
  
  class Person:
      def __init__(self, name=None, age=None, address=None):
          self.name = name
          self.age = int(age)
          self.address = Address(**address)
  
  def as_person(jdict):
      if u'person' in jdict:
          print('person found')
          person = jdict[u'person']
          return Person(name=person[u'name'], age=person[u'age'], 
                        address=person[u'address'])
      else:
          return('person not found')
          return jdict
  </code></pre>
  
  <p>(I define classes with keyword args to provide defaults so that the json need not contain all elements, and I can still ensure that the attributes are present in the class instance. I will also eventually associate methods with the classes, but want to populate the instances from json data.)</p>
  
  <p>If I run:</p>
  
  <pre><code>&gt;&gt;&gt; p = as_person(json.loads(jstr))
  </code></pre>
  
  <p>I get what I expect, ie:</p>
  
  <pre><code>person found
  </code></pre>
  
  <p>and p becomes a Person object, ie:</p>
  
  <pre><code>&gt;&gt;&gt; pprint(p.__dict__)
  {'address': &lt;__main__.Address instance at 0x0615F3C8&gt;,
   'age': 46,
   'name': u'John Doe'}
  &gt;&gt;&gt; pprint(p.address.__dict__)
  {'city': u'Boston', 'state': u'MA', 'street': u'4 Yawkey Way'}
  </code></pre>
  
  <p>However, if instead, I try to use:</p>
  
  <pre><code>&gt;&gt;&gt; p = json.loads(jstr, object_hook=as_person)
  </code></pre>
  
  <p>I get:</p>
  
  <pre><code>person found
  Traceback (most recent call last):
    File "&lt;interactive input&gt;", line 1, in &lt;module&gt;
    File "C:\Program Files (x86)\Python27\lib\json\__init__.py", line 339, in loads
      return cls(encoding=encoding, **kw).decode(s)
    File "C:\Program Files (x86)\Python27\lib\json\decoder.py", line 366, in decode
      obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    File "C:\Program Files (x86)\Python27\lib\json\decoder.py", line 382, in 
  raw_decode
      obj, end = self.scan_once(s, idx)
    File "&lt;interactive input&gt;", line 5, in as_person
  TypeError: string indices must be integers, not unicode
  </code></pre>
  
  <p>I have no idea why this would happen, and suspect there is some subtlety around how the object_hook mechanism works that I'm missing.</p>
  
  <p>In an attempt to incorporate the notion from the aforementioned question, which was that the object_hook evaluates each nested dictionary from the bottom up (and replaces it in the traverse?) I also tried:</p>
  
  <pre><code>def as_person2(jdict):
      if u'person' in jdict:
          print('person found')
          person = jdict[u'person']
          return Person2(name=person[u'name'], age=person[u'age'], address=person[u'address'])
      elif u'address' in jdict:
          print('address found')
          return Address(jdict[u'address'])
      else:
          return('person not found')
          return jdict
  
  &gt;&gt;&gt; json.loads(jstr, object_hook=as_person2)
  address found
  person found
  Traceback (most recent call last):
    File "&lt;interactive input&gt;", line 1, in &lt;module&gt;
    File "C:\Program Files (x86)\Python27\lib\json\__init__.py", line 339, in loads
      return cls(encoding=encoding, **kw).decode(s)
    File "C:\Program Files (x86)\Python27\lib\json\decoder.py", line 366, in decode
      obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    File "C:\Program Files (x86)\Python27\lib\json\decoder.py", line 382, in raw_decode
      obj, end = self.scan_once(s, idx)
    File "&lt;interactive input&gt;", line 5, in as_person2
  AttributeError: Address instance has no attribute '__getitem__'
  </code></pre>
  
  <p>So, clearly, the proper form of the object_hook function is escaping me.</p>
  
  <p>Can someone explain in detail how the object_hook mechanism works, and how the resulting object tree is supposed to be recursively constructed from the bottom up, why my code doesn't work as expected, and either fix my example or provide one that uses an object_hook function to build a complex class, given that you only get the one object_hook function?</p>