FixedPoint

Alex Martelli aleax at aleax.it
Fri Feb 8 11:08:06 EST 2002


Mark McEahern wrote:
        ...
>> Hmm., while we're at it, we should probably change this test too: "in
>> [ListType, TupleType]" Does anybody know how I can reliably test if
>> something is a Sequence or is iterable?
> 
> I'm just thinking out loud here...  How about something like this:
> 
> if hasattr(value, '__getitem__'):
> ...
> 
> This may only work in 2.2:
> 
> if hasattr(value, '__iter__'):
> ...
> 
> I don't really have a good grasp of all the subtleties involved in testing
> for sequence in a way that works across lots of different versions of
> Python.

"something is iterable" if and only if you can iterate on it.  So, try 
iterating on it, and handle the resulting exception should it turn out
you can't.  I'm not sure exactly what exceptions would be raised by
various versions of Python -- probably a TypeError, but one never
knows -- better to experiment on all relevant versions, or maybe, just
for once, a generic try/except is acceptable.  An almost acceptable
version might therefore be:

def isIterable(x):
    try:
        for i in x: return 1   # iterable
        else: return 1         # iterable, although empty
    except:
        return 0

Unfortunately, if we're in Python 2.2 and x is an iterator, isIterable
"consumes" x's first item.  This isn't hard to fix:

def isIterable(x):
    try: x=iter(x)
    except: pass
    else: return 1
    try:
        for i in x: return 1   # iterable
        else: return 1         # iterable, although empty
    except:
        return 0

This assumes function iter, if defined, is "sensible" -- it returns an
iterator, or else raises an exception.  Builtin function iter does meet
this requirement (it raises a TypeError if __iter__ is defined but
returns a non-iterator), and (as usual in Python) it seems sensible
to assume that if somebody has replaced a builtin function then that 
somebody is responsible for the overall results still being sensible.

Of course, this does return different results for similar objects in 
various Python releases -- as it should: a file or dict is iterable in 
Python 2.2, but not in 2.1 or earlier, after all.

As noticed in a following post, "is this iterable" or "is this a sequence" 
may or may not be what you really want to know -- strings and Unicode 
objects are iterable sequences, for example, yet often we want to treat 
them as 'atoms', depending on context.  So you need to determine what 
exactly you DO want to check.  Once again, if you want to exclude string, 
UserString, Unicode objects, and so on, don't typetest -- use try/except:

def isStringLike(x):
    try: x+''
    except TypeError: return 0
    else: return 1

You may want to use different definitions for "is string-like", but 
personally I've found that "lets an empty string be concatenated to it" is 
a pragmatically useful definition.


Alex




More information about the Python-list mailing list