is_iterable function.

Neil Cerutti horpner at yahoo.com
Thu Jul 26 11:02:39 EDT 2007


Based on the discussions in this thread (thanks all for your
thoughts), I'm settling for:

def is_iterable(obj):
  try:
    iter(obj).next()
    return True
  except TypeError:
    return False
  except KeyError:
    return False

The call to iter will fail for objects that don't support the
iterator protocol, and the call to next will fail for a
(hopefully large) subset of the objects that don't support the
sequence protocol.

This seems preferable to cluttering code with exception handling
and inspecting tracebacks. But it's still basically wrong, I
guess.

To repost my use case:

def deeply_mapped(func, iterable):
    """ Recursively apply a function to every item in a iterable object,
    recursively descending into items that are iterable. The result is an
    iterator over the mapped values. Similar to the builtin map function, func
    may be None, causing the items to returned unchanged.

    >>> import functools
    >>> flattened = functools.partial(deeply_mapped, None)
    >>> list(flattened([[1], [2, 3, []], 4]))
    [1, 2, 3, 4]

    >>> list(flattened(((1), (2, 3, ()), 4)))
    [1, 2, 3, 4]

    >>> list(flattened([[[[]]], 1, 2, 3, 4]))
    [1, 2, 3, 4]

    >>> list(flattened([1, [[[2, 3]], 4]]))
    [1, 2, 3, 4]

    """
    for item in iterable:
        if is_iterable(item):
            for it in deeply_mapped(func, item):
                if func is None:
                    yield it
                else:
                    yield func(it)
        else:
            if func is None:
                yield item
            else:
                yield func(item)
-- 
Neil Cerutti



More information about the Python-list mailing list