Как я могу проверить, является ли объект итератором в Python? - PullRequest
34 голосов
/ 11 июня 2010

Я могу проверить метод next(), но достаточно ли этого? Есть ли идеоматический путь?

Ответы [ 7 ]

54 голосов
/ 11 июня 2010

В Python 2.6 или выше, встроенная идиома для таких поведенческих проверок - это «проверка членства» с абстрактным базовым классом в модуле collections стандартной библиотеки:

>>> import collections
>>> isinstance('ciao', collections.Iterable)
True
>>> isinstance(23, collections.Iterable)
False
>>> isinstance(xrange(23), collections.Iterable)
True

Действительно, этот вид проверок является основной причиной проектирования новых абстрактных базовых классов (второй важный момент заключается в предоставлении «смешанной функциональности» в некоторых случаях, именно поэтому они представляют собой 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)

Редактировать : как указано в комментарии, вопрос сосредоточен на том, является ли объект итерацией *** ator ***, а не тем, является ли он *** способным *** (все итераторы) итерируемы, но не наоборот - не все итерируемые являются итераторами). isinstance(x, collections.Iterator) - это совершенно аналогичный способ проверки именно этого условия.

15 голосов
/ 11 июня 2010

Объект является итеративным, если он реализует протокол итератора.
Вы можете проверить наличие метода __iter__() с помощью:

hasattr(object,'__iter__')

в Python 2.x этот подход пропускает объекты str и другие встроенные типы последовательностей, такие как юникод, xrange, буфер. Работает на Python 3.

Другой способ - протестировать его методом iter:

try:
   iter(object)
except TypeError:
   #not iterable
6 голосов
/ 26 марта 2016

Чтобы быть итератором, объект должен пройти три теста:

  • obj имеет метод __iter__
  • obj имеет метод next (или __next__ в Python 3)
  • obj.__iter__() возвращает obj

Таким образом, тест с проверкой на себя будет выглядеть так:

def is_iterator(obj):
    if (
            hasattr(obj, '__iter__') and
            hasattr(obj, 'next') and      # or __next__ in Python 3
            callable(obj.__iter__) and
            obj.__iter__() is obj
        ):
        return True
    else:
        return False
0 голосов
/ 30 марта 2019

Этот пример взят из книги Effective Python и проиллюстрирован в этой публикации .

Итерация создает итератор.Любой итератор также является итератором, но выдает себя в качестве итератора:

>>> list_iter = iter([])
>>> iter(list_iter) is list_iter
True
0 голосов
/ 29 декабря 2018

Существует лучший метод, чем предлагали другие ответы.

В Python у нас есть два вида вещей: Iterable и Iterator.Объект - Iterable, если он может дать вам Iterator.Это происходит, когда вы используете iter().Объект является Iterator, если вы можете использовать next() для последовательного просмотра его элементов.Например, map() возвращает Iterator, а list - Iterable.

Вот подробнее .

Ниже приведен код для проверки этих типов:

from collections.abc import Iterable, Iterator

r = [1, 2, 3]
e = map(lambda x:x, r)

print(isinstance(r, Iterator)) # False, because can't apply next
print(isinstance(e, Iterator)) # True
print(isinstance(r, Iterable)) # True, because can apply iter()
print(isinstance(e, Iterable)) # True, note iter() returns self
0 голосов
/ 22 ноября 2018

Поскольку вопрос об итераторе, а не итерации, и об использовании итератора, самый простой и питонский способ сделать это

iterable = [1,2]
iterator = iter(iterable)


def isIterator(obj):
    try:
        next(obj, None)
        return True
    except TypeError:
        return False

>>> isIterator(iterable)
False
>>> isIterator(iterator)
True

Да. Проверка на next () должна быть достаточной

0 голосов
/ 19 июля 2018

ответ из комментариев к документации по исходному коду Python:

{путь установки python} /Versions/3.5/lib/python3.5/types.py

# Iterators in Python aren't a matter of type but of protocol.  A large
# and changing number of builtin types implement *some* flavor of
# iterator.  Don't check the type!  Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...