Recurse down Models, HasProps, and Python containers

    The ordering in this function is to optimize performance.  We check the
    most comomn types (int, float, str) first so that we can quickly return in
    the common case.  We avoid isinstance and issubclass checks in a couple
    places with `type` checks because isinstance checks can be slow.

def _visit_value_and_its_immediate_references(obj, visitor):
    ''' Recurse down Models, HasProps, and Python containers

    The ordering in this function is to optimize performance.  We check the
    most comomn types (int, float, str) first so that we can quickly return in
    the common case.  We avoid isinstance and issubclass checks in a couple
    places with `type` checks because isinstance checks can be slow.
    '''
    typ = type(obj)
    if typ in _common_types:  # short circuit on common base types
        return
    if typ is list or issubclass(typ, (list, tuple)):  # check common containers
        for item in obj:
            _visit_value_and_its_immediate_references(item, visitor)
    elif issubclass(typ, dict):
        for key, value in iteritems(obj):
            _visit_value_and_its_immediate_references(key, visitor)
            _visit_value_and_its_immediate_references(value, visitor)
    elif issubclass(typ, HasProps):
        if issubclass(typ, Model):
            visitor(obj)
        else:
            # this isn't a Model, so recurse into it
            _visit_immediate_value_references(obj, visitor)