This function returns a generator which iterates over the collection,
    similar to Collection.itertuples().  Collections are viewed by this module,
    regardless of type, as a mapping from an index to the value.  For sets, the
    "index" is the value itself (ie, (V, V)).  For dicts, it's a string, and
    for lists, it's an int.

    In general, this function defers to ``itertuples`` and/or ``iteritems``
    methods defined on the instances; however, when duck typing, this function
    typically provides the generator.

def collection_generator(collection):
    """This function returns a generator which iterates over the collection,
    similar to Collection.itertuples().  Collections are viewed by this module,
    regardless of type, as a mapping from an index to the value.  For sets, the
    "index" is the value itself (ie, (V, V)).  For dicts, it's a string, and
    for lists, it's an int.

    In general, this function defers to ``itertuples`` and/or ``iteritems``
    methods defined on the instances; however, when duck typing, this function
    typically provides the generator.
    """
    if collection is _nothing:

        def generator():
            if False:
                yield any

    elif hasattr(collection, "itertuples"):
        return collection.itertuples()
    elif hasattr(collection, "keys"):

        def generator():
            for key in collection.keys():
                yield (key, collection[key])

    elif hasattr(collection, "items"):
        return collection.items()
    elif hasattr(collection, "iteritems"):
        return collection.iteritems()
    elif hasattr(collection, "__getitem__"):

        def generator():
            i = 0
            for item in collection:
                yield (i, item)
                i += 1

    else:

        def generator():
            for item in collection:
                yield (item, item)

    return generator()