В Python интерфейс итерабельного является подмножеством iterator interface. Это имеет то преимущество, что во многих случаях их можно рассматривать одинаково. Однако между ними существует важная смысловая разница, поскольку для итерабельного __iter__
возвращает новый объект итератора, а не только self
. Как я могу проверить, что итерабельность действительно является итерабельным, а не итератором? Концептуально я понимаю, что iterables являются коллекциями, в то время как итератор управляет только итерацией (т. Е. Отслеживает позицию), но не является самой коллекцией.Как отличить итератор от итерации?
Разница, например, важна, когда требуется несколько циклов. Если итератор задан, второй цикл не будет работать, так как итератор уже был использован и напрямую вызывает StopIteration
.
Заманчиво протестировать метод next
, но это кажется опасным и как-то не так. Должен ли я просто проверить, что второй цикл был пуст?
Есть ли способ сделать такой тест более питоническим способом? Я знаю, что это звучит как классический случай LBYL против EAFP, так что, может быть, я просто должен отказаться? Или я чего-то не хватает?
Edit: С. Лотт говорит в своем ответе ниже, что это в первую очередь проблема в желании сделать несколько проходов над итератора, и что не следует делать это в первую очередь. Однако в моем случае данные очень большие, и в зависимости от ситуации необходимо многократно передавать данные для обработки данных (абсолютно нет способа обойти это).
Итерируемый также предоставляется пользователем, и для ситуаций, когда одного прохода достаточно, он будет работать с итератором (например, созданным генератором для простоты). Но было бы неплохо защититься от случая, когда пользователь предоставляет только итератор, когда требуется несколько проходов.
Edit 2: На самом деле это очень хороший пример для Abstract Base Classes. Методы __iter__
в итераторе и итерабеле имеют одно и то же имя, но семантически разные! Таким образом, hasattr
бесполезен, но isinstance
обеспечивает чистое решение.
Вау, это, кажется, ответ, который я искал, спасибо! Я подожду немного, прежде чем принимать его, если кто-то может указать на проблему. – nikow
Ну, проблема в том, что один «пустой» вызов obj .__ iter __(), но я не вижу другого надежного способа сделать это. – vartec
Хотя я не знаю контр-пример, это не * гарантировано * для работы. – tzot