Answer a question

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

Answers

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
Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐