I would like to iterate over the outputs of an unknown function. Unfortunately I do not know whether the function returns a single item or a tuple. This must be a standard problem and there must be a standard way of dealing with this -- what I have now is quite ugly.
x = UnknownFunction()
if islist(x):
iterator = x
else:
iterator = [x]
def islist(s):
try:
len(s)
return True
except TypeError:
return False
for ii in iterator:
#do stuff
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
所有评论(0)