I have a function that take an argument which can be either a single item or a double item:
def iterable(arg) if #arg is an iterable: print "yes" else: print "no"
so that:
>>> iterable( ("f","f") ) yes >>> iterable( ["f","f"] ) yes >>> iterable("ff") no
The problem is that string is technically iterable, so I can't just catch the ValueError when trying arg[1]
. I don't want to use isinstance(), because that's not good practice (or so I'm told).
As of Python 3.4, the most accurate way to check whether an object x is iterable is to call iter(x) and handle a TypeError exception if it isn't. This is more accurate than using isinstance(x, abc. Iterable) , because iter(x) also considers the legacy __getitem__ method, while the Iterable ABC does not.
Strings are iterable; iteration over a string yields each of its 1-byte substrings in order. But String doesn't implement Iterable 's Iterate method.
String is iterable Arrays and strings are most widely used built-in iterables.
An object is Iterable if it can give you Iterator . It does so when you use iter() on it. An object is Iterator if you can use next() to sequentially browse through its elements. For example, map() returns Iterator and list is Iterable .
Use isinstance (I don't see why it's bad practice)
import types if not isinstance(arg, types.StringTypes):
Note the use of StringTypes. It ensures that we don't forget about some obscure type of string.
On the upside, this also works for derived string classes.
class MyString(str): pass isinstance(MyString(" "), types.StringTypes) # true
Also, you might want to have a look at this previous question.
Cheers.
NB: behavior changed in Python 3 as StringTypes
and basestring
are no longer defined. Depending on your needs, you can replace them in isinstance
by str
, or a subset tuple of (str, bytes, unicode)
, e.g. for Cython users. As @Theron Luhn mentionned, you can also use six
.
As of 2017, here is a portable solution that works with all versions of Python:
#!/usr/bin/env python import collections import six def iterable(arg): return ( isinstance(arg, collections.Iterable) and not isinstance(arg, six.string_types) ) # non-string iterables assert iterable(("f", "f")) # tuple assert iterable(["f", "f"]) # list assert iterable(iter("ff")) # iterator assert iterable(range(44)) # generator assert iterable(b"ff") # bytes (Python 2 calls this a string) # strings or non-iterables assert not iterable(u"ff") # string assert not iterable(44) # integer assert not iterable(iterable) # function
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With