The most general solution to this problem is to use isinstance
with the abstract base class collections.Iterable
.
import collections
def get_iterable(x):
if isinstance(x, collections.Iterable):
return x
else:
return (x,)
You might also want to test for basestring
as well, as Kindall suggests.
if isinstance(x, collections.Iterable) and not isinstance(x, basestring):
Now some people might think, as I once did, "isn't isinstance
considered harmful? Doesn't it lock you into using one kind of type? Wouldn't using hasattr(x, '__iter__')
be better?"
The answer is: not when it comes to abstract base classes. In fact, you can define your own class with an __iter__
method and it will be recognized as an instance of collections.Iterable
, even if you do not subclass collections.Iterable
. This works because collections.Iterable
defines a __subclasshook__
that determines whether a type passed to it is an Iterable by whatever definition it implements.
>>> class MyIter(object):
... def __iter__(self):
... return iter(range(10))
...
>>> i = MyIter()
>>> isinstance(i, collections.Iterable)
True
>>> collections.Iterable.__subclasshook__(type(i))
True