Type masquerading using dynamic base classes

Python allows us to construct new classes on-the-fly with type(). By (ab)using this feature we can construct a class that preserves its own interface while assuming all of the behaviour of an existing object. Useful for wrapping compound types such as dictionaries, lists, sets, etc. without having to proxy __getitem__, __iter__ and so on, or write a custom __getattr__.

One example of when this could be useful is a JSON-specific HTTP client object that assumes the type of the JSON data, while maintaining response-specific attributes such as headers and status:

import simplejson


class Response(object):
  """A response object that masquerades as the decoded content type."""
  def __new__(cls, content=None, headers=None, status=None):
    if content is not None:
      content = simplejson.loads(content)
      assumed_type = type(content)

      bases = (Response, assumed_type)
      name = assumed_type.__name__.title() + 'Response'
      cls = type(name, bases, {})

      self = assumed_type.__new__(cls, content)
      self.assumed_type = assumed_type
    else:
      self = object.__new__(cls)
    return self

  def __init__(self, content=None, headers=None, status=None):
    if content is not None:
      super(Response, self).__init__(content)
    self.headers = headers
    self.status = status


json_data = [
  '{"foo": 1, "bar": 2}',
  '123',
  '123.5',
  '["foo", "bar"]',
  ]


for data in json_data:
  response = Response(data, headers=[('Content-Type', 'application/json')],
                      status=200)
  decoded = simplejson.loads(data)
  print response
  print '  Same type?', isinstance(response, type(decoded))
  try:
    print '  Iteration:',
    print [i for i in response]
  except TypeError:
    print '(type does not support iteration)'
  print '  Headers:', response.headers
  print '  Status:', response.status
  print

Outputs this:

{u'foo': 1, u'bar': 2}
  Same type? True
  Iteration: [u'foo', u'bar']
  Headers: [('Content-Type', 'application/json')]
  Status: 200

123
  Same type? True
  Iteration: (type does not support iteration)
  Headers: [('Content-Type', 'application/json')]
  Status: 200

123.5
  Same type? True
  Iteration: (type does not support iteration)
  Headers: [('Content-Type', 'application/json')]
  Status: 200

[u'foo', u'bar']
  Same type? True
  Iteration: [u'foo', u'bar']
  Headers: [('Content-Type', 'application/json')]
  Status: 200