def determineClass(o):
  return hasattr(o, '__class__') and o.__class__ or type(o)

class Recorder(object):
  def __init__(self): self._account = {}
  def __call__(self, o):
    a = self._account
    class_ = determineClass(o)
    if class_ in a: a[class_] += 1
    else: a[class_] = 1
  def account(self): return self._account

def sortRecords(recorder):
  return sorted(recorder.account().items(), key=lambda r: r[1], reverse=True)

def fix((ty, no)):
  '''some types apparently have a broken 'str'. Fix this.'''
  try: tyn = str(ty)
  except TypeError:
    try: tyn = 'BROKEN-STR: %r' % ty
    except TypeError: tyn = 'BROKEN-STR-AND-REPR'
  return tyn, no

def analyseObjects(limit=100):
  '''analyses live objects and garbage.

  The result is a pair with information for live and garbage objects, respectively.
  The information is a dict with keys 'count' and 'sorted'.
  'count' is the total number of objects, 'sorted' a list with pairs
  'type' and 'instanceCount', inverse sorted by 'instanceCount'.
  '''
  result = []
  import gc
  for objs in gc.get_objects(), gc.garbage:
    r = Recorder()
    for o in objs: r(o)
    result.append({
      'count':len(objs),
      'sorted':map(fix, sortRecords(r)[:limit]),
      })
  return result

