is_iterable function.

George Sakkis george.sakkis at gmail.com
Thu Jul 26 23:20:18 CEST 2007


On Jul 26, 2:56 pm, Neil Cerutti <horp... at yahoo.com> wrote:
> On 2007-07-26, Marc 'BlackJack' Rintsch <bj_... at gmx.net> wrote:
>
>
>
> > On Thu, 26 Jul 2007 15:02:39 +0000, Neil Cerutti wrote:
>
> >> 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.
>
> > And the `next()` consumes an element if `obj` is not
> > "re-iterable".
>
> Crap.
>
> So how best to imlement deeply_mapped?
>
> The following still breaks for objects that don't provide
> __iter__, do provide __getitem__, but don't support the sequence
> protocol.

That's not the only problem; try a string element to see it break too.
More importantly, do you *always* want to handle strings as
iterables ?

The best general way to do what you're trying to is pass is_iterable()
as an optional argument with a
sensible default, but allow the user to pass a different one that is
more appropriate for the task at hand:

def is_iterable(obj):
    try: iter(obj)
    except: return False
    else: return True

def flatten(obj, is_iterable=is_iterable):
    if is_iterable(obj):
        for item in obj:
            for flattened in flatten(item, is_iterable):
                yield flattened
    else:
        yield obj

from functools import partial
flatten_nostr = partial(flatten, is_iterable=lambda obj: not
isinstance(obj,basestring)
                                                         and
is_iterable(obj))

print list(flatten_nostr([1, [[[2, 'hello']], (4, u'world')]]))


By the way, it's bad design to couple two distinct tasks: flattening a
(possibly nested) iterable and applying a function to its elements.
Once you have a flatten() function, deeply_mapped is reduced down to
itertools.imap.

HTH,
George




More information about the Python-list mailing list