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

前端 未结 21 2189
太阳男子
太阳男子 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 01:05
    1. Checking for __iter__ works on sequence types, but it would fail on e.g. strings in Python 2. I would like to know the right answer too, until then, here is one possibility (which would work on strings, too):

      from __future__ import print_function
      
      try:
          some_object_iterator = iter(some_object)
      except TypeError as te:
          print(some_object, 'is not iterable')
      

      The iter built-in checks for the __iter__ method or in the case of strings the __getitem__ method.

    2. Another general pythonic approach is to assume an iterable, then fail gracefully if it does not work on the given object. The Python glossary:

      Pythonic programming style that determines an object's type by inspection of its method or attribute signature rather than by explicit relationship to some type object ("If it looks like a duck and quacks like a duck, it must be a duck.") By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using type() or isinstance(). Instead, it typically employs the EAFP (Easier to Ask Forgiveness than Permission) style of programming.

      ...

      try:
         _ = (e for e in my_object)
      except TypeError:
         print my_object, 'is not iterable'
      
    3. The collections module provides some abstract base classes, which allow to ask classes or instances if they provide particular functionality, for example:

      from collections.abc import Iterable
      
      if isinstance(e, Iterable):
          # e is iterable
      

      However, this does not check for classes that are iterable through __getitem__.

    0 讨论(0)
  • 2020-11-22 01:05

    The best solution I've found so far:

    hasattr(obj, '__contains__')

    which basically checks if the object implements the in operator.

    Advantages (none of the other solutions has all three):

    • it is an expression (works as a lambda, as opposed to the try...except variant)
    • it is (should be) implemented by all iterables, including strings (as opposed to __iter__)
    • works on any Python >= 2.5

    Notes:

    • the Python philosophy of "ask for forgiveness, not permission" doesn't work well when e.g. in a list you have both iterables and non-iterables and you need to treat each element differently according to it's type (treating iterables on try and non-iterables on except would work, but it would look butt-ugly and misleading)
    • solutions to this problem which attempt to actually iterate over the object (e.g. [x for x in obj]) to check if it's iterable may induce significant performance penalties for large iterables (especially if you just need the first few elements of the iterable, for example) and should be avoided
    0 讨论(0)
  • 2020-11-22 01:05

    It's always eluded me as to why python has callable(obj) -> bool but not iterable(obj) -> bool...
    surely it's easier to do hasattr(obj,'__call__') even if it is slower.

    Since just about every other answer recommends using try/except TypeError, where testing for exceptions is generally considered bad practice among any language, here's an implementation of iterable(obj) -> bool I've grown more fond of and use often:

    For python 2's sake, I'll use a lambda just for that extra performance boost...
    (in python 3 it doesn't matter what you use for defining the function, def has roughly the same speed as lambda)

    iterable = lambda obj: hasattr(obj,'__iter__') or hasattr(obj,'__getitem__')
    

    Note that this function executes faster for objects with __iter__ since it doesn't test for __getitem__.

    Most iterable objects should rely on __iter__ where special-case objects fall back to __getitem__, though either is required for an object to be iterable.
    (and since this is standard, it affects C objects as well)

    0 讨论(0)
提交回复
热议问题