Returns whether value is iterable.
    
    ``include_maps``
        Maps are technically iterable, defaulting to their keys, but you 
        commonly want to find if it is a list-like type and leave maps alone,
        so this is False by default.
        
    ``include_sets``
        Sets are also technically iterable and can be treated like lists, but
        sometimes you don't want to include sets. Defaults to True.
        
    Strings are not considered iterable, even though you can iterate over them
    if you really want to, because the ``__iter__`` method is not defined for
    them by Python. This is usually a good thing -- you probably don't want
    to iterate over the characters of a string by accident.

def is_iterable(value, include_maps=False, include_sets=True):
    """Returns whether value is iterable.
    
    ``include_maps``
        Maps are technically iterable, defaulting to their keys, but you 
        commonly want to find if it is a list-like type and leave maps alone,
        so this is False by default.
        
    ``include_sets``
        Sets are also technically iterable and can be treated like lists, but
        sometimes you don't want to include sets. Defaults to True.
        
    Strings are not considered iterable, even though you can iterate over them
    if you really want to, because the ``__iter__`` method is not defined for
    them by Python. This is usually a good thing -- you probably don't want
    to iterate over the characters of a string by accident.
    """
    if hasattr(value, '__iter__'):
        if not include_maps and hasattr(value, 'keys'):
            return False
        if not include_sets and hasattr(value, 'isdisjoint'):
            return False
        return True
    else:
        return False