Returns the :class:`Instance` of the specified object if it is one that
    we track by default.

    Args:
        obj (object): any python object passed as an argument to a method.

    Returns:
        Instance: if the object is trackable, the Instance instance of
          that object; else None.

def tracker(obj):
    """Returns the :class:`Instance` of the specified object if it is one that
    we track by default.

    Args:
        obj (object): any python object passed as an argument to a method.

    Returns:
        Instance: if the object is trackable, the Instance instance of
          that object; else None.
    """
    import types as typ
    global oids, uuids
    import six
    from inspect import isclass
    untracked = (six.string_types, six.integer_types, float,
                 complex, six.text_type)

    semitrack = (list, dict, set, tuple)
    if six.PY3: # pragma: no cover
        semitrack = semitrack + (range, filter, map)
        
    if (isinstance(obj, semitrack) and
        all([isinstance(t, untracked) for t in obj])):
        if len(obj) > 0:
            semiform = "{0} len={1:d} min={2} max={3}"
            return semiform.format(type(obj), len(obj), min(obj), max(obj))
        else:
            semiform = "{0} len={1:d}"
            return semiform.format(type(obj), len(obj))
    elif isinstance(obj, semitrack):
        #We have to run the tracker on each of the elements in the list, set,
        #dict or tuple; this is necessary so that we can keep track of
        #subsequent calls made with unpacked parts of the tuple.
        result = []

        #If we get a list of 10K tuples (like plot points in matplotlib), then
        #this pollutes the database. So, we restrict the maximum size of complex
        #lists to be 5; we track the first 5 objects and then store a summary of
        #the remaining information.
        for o in obj[0:min((len(obj), 5))]:
            track = tracker(o)
            if isinstance(track, Instance):
                result.append(track.uuid)
            else:
                result.append(track)

        if len(obj) > 5:
            result.append("... ({0:d} items)".format(len(obj)))
            
        return tuple(result)
    elif isinstance(obj, slice):
        return "slice({}, {}, {})".format(obj.start, obj.stop, obj.step)
    elif type(obj) is type:
        return obj.__name__
    elif type(obj) is typ.LambdaType:
        if hasattr(obj, "__fqdn__"):
            #We need to get the actual fqdn of the object *before* it was
            #decorated.
            return obj.__fqdn__
        else:
            if six.PY2:
                _code = obj.func_code
            else: # pragma: no cover
                _code = obj.__code__
            return "lambda ({})".format(', '.join(_code.co_varnames))
    elif type(obj) in [typ.FunctionType, typ.MethodType]: # pragma: no cover
        return obj.__name__
    elif not isinstance(obj, untracked):
        #For many of the numpy/scipy methods, the result is a tuple of numpy
        #arrays. In that case, we should maintain the tuple structure for
        #descriptive purposes, but still return a tracker.
        oid = id(obj)
        if oid in oids:
            result = oids[oid]
        else:
            result = Instance(oid, obj)
            oids[oid] = result
            uuids[result.uuid] = result
        return result
    else:
        return None