In Python, how do I determine if an object is iterable?

前端 未结 21 2245
太阳男子
太阳男子 2020-11-22 00:35

Is there a method like isiterable? The only solution I have found so far is to call

hasattr(myObj, \'__iter__\')

But I am not

21条回答
  •  梦谈多话
    2020-11-22 00:44

    In Python <= 2.5, you can't and shouldn't - iterable was an "informal" interface.

    But since Python 2.6 and 3.0 you can leverage the new ABC (abstract base class) infrastructure along with some builtin ABCs which are available in the collections module:

    from collections import Iterable
    
    class MyObject(object):
        pass
    
    mo = MyObject()
    print isinstance(mo, Iterable)
    Iterable.register(MyObject)
    print isinstance(mo, Iterable)
    
    print isinstance("abc", Iterable)
    

    Now, whether this is desirable or actually works, is just a matter of conventions. As you can see, you can register a non-iterable object as Iterable - and it will raise an exception at runtime. Hence, isinstance acquires a "new" meaning - it just checks for "declared" type compatibility, which is a good way to go in Python.

    On the other hand, if your object does not satisfy the interface you need, what are you going to do? Take the following example:

    from collections import Iterable
    from traceback import print_exc
    
    def check_and_raise(x):
        if not isinstance(x, Iterable):
            raise TypeError, "%s is not iterable" % x
        else:
            for i in x:
                print i
    
    def just_iter(x):
        for i in x:
            print i
    
    
    class NotIterable(object):
        pass
    
    if __name__ == "__main__":
        try:
            check_and_raise(5)
        except:
            print_exc()
            print
    
        try:
            just_iter(5)
        except:
            print_exc()
            print
    
        try:
            Iterable.register(NotIterable)
            ni = NotIterable()
            check_and_raise(ni)
        except:
            print_exc()
            print
    

    If the object doesn't satisfy what you expect, you just throw a TypeError, but if the proper ABC has been registered, your check is unuseful. On the contrary, if the __iter__ method is available Python will automatically recognize object of that class as being Iterable.

    So, if you just expect an iterable, iterate over it and forget it. On the other hand, if you need to do different things depending on input type, you might find the ABC infrastructure pretty useful.

提交回复
热议问题