Я могу проверить на a next()
метод, но то, что достаточно? Существует ли идиоматический путь?
В Python 2. 6 или лучше, встроенная идиома для таких проверок поведения - это "проверка принадлежности" к абстрактному базовому классу в collections
модуле стандартной библиотеки:
>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True
Действительно, такого рода проверки являются основной причиной дизайна новых абстрактных базовых классов (второй важной причиной является обеспечение "функциональности mixin" в некоторых случаях, вот почему они ABC, а не просто интерфейсы - но это не относится к collections. Iterable
, она существует строго, чтобы позволить такие проверки с помощью isinstance
или issubclass
). ABC позволяют классам, которые фактически не наследуются от них, быть "зарегистрированными" как подклассы в любом случае, так что такие классы могут быть "подклассами" ABC для таких проверок; и они могут внутренне выполнять все необходимые проверки для специальных методов (__iter__
в данном случае), так что вам не придется этого делать.
Если вы застряли со старыми версиями Python, "лучше попросить прощения, чем разрешения":
def isiterable(x):
try: iter(x)
except TypeError: return False
else: return True
но это не так быстро и лаконично, как новый подход.
Обратите внимание, что для этого особого случая вам часто потребуется особый случай строк (которые итерируемы, но в большинстве приложений все равно должны рассматриваться как "скаляры"). Какой бы подход вы ни использовали для проверки итерабельности, если вам нужна такая специальная оболочка, просто добавьте проверку на isinstance(x, basestring)
- например:
def reallyiterable(x):
return not isinstance(x, basestring) and isinstance(x, collections.Iterable)
Edit: как указано в комментарии, вопрос фокусируется на том, является ли объект итератором***, а не итерабельным*** (все итераторы итерабельны, но не наоборот - не все итерабельные являются итераторами). isinstance(x, collections.Iterator)
- это совершенно аналогичный способ проверки именно этого условия.
Объект является итеративным, если он реализует протокол итератора.
Вы можете проверить наличие метода __ iter __ ()
с помощью:
hasattr(object,'__iter__')
в Python 2.x этот подход пропускает объекты str и другие встроенные типы последовательностей, такие как unicode, xrange, buffer. Он работает в Python 3.
Другой способ - протестировать его с помощью метода iter:
try:
iter(object)
except TypeError:
#not iterable