is parameter an iterable?
Steven D'Aprano
steve at REMOVETHIScyber.com.au
Tue Nov 15 17:57:59 EST 2005
On Tue, 15 Nov 2005 11:26:23 -0800, py wrote:
> Dan Sommers wrote:
>> Just do it. If one of foo's callers passes in a non-iterable, foo will
>> raise an exception, and you'll catch it during testing
>
> That's exactly what I don't want. I don't want an exception, instead I
> want to check to see if it's an iterable....if it is continue, if not
> return an error code. I can't catch it during testing since this is
> going to be used by other people.
That would be the Look Before You Leap school of thought.
That is rarely the best way of doing things in Python. (Note I said
*rarely*, not *never*.) If you insist, you would have to do something like
this:
def is_iterable(obj):
"""Returns True if obj is *probably* an iterable and False
otherwise. Not that some weird custom objects that break the
rules may give incorrect results.
"""
if type(obj) in (type([]), type(()), type("")):
return True
elif hasattr(obj, next) and callable(obj.next):
return True
elif hasattr(obj, __getitem__):
return True
else:
# I don't think I missed anything...
return False
But in fact there is an easier way:
def is_iterable(obj):
"""Just Do It."""
try:
for item in obj:
break
except TypeError:
return False
return True
That works, but it has a side-effect: if you pass it an iterable that gets
consumed, you now have used up the first item of it (e.g. if you a
reading lines from a file, you've just used the first line and won't get
it back unless you reset the file pointer).
So do your test inside your code:
def foo(inputVal):
try:
for val in inputVal:
# do stuff
except TypeError, msg:
if msg == "iteration over non-sequence":
# handle non-iterable case
else:
# some other TypeError is a bug, so re-raise the exception
raise
More information about the Python-list
mailing list