1

I'm creating an interator like so:

some_list = [1,2,5,12,30,75,180,440]
iter(some_list)

I have a need to access the current value of an iterator again. Is there a current() method that allows me to stay on the same position?

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
Terrence Brannon
  • 4,760
  • 7
  • 42
  • 61
  • 5
    Could you expand your question? (Maybe with how this code would be used.) I'm not sure I understand. – Cameron Apr 23 '13 at 01:44
  • 1
    Are you looking for [`itertools.tee`](http://docs.python.org/2/library/itertools.html#itertools.tee)? – abarnert Apr 23 '13 at 01:45
  • 2
    Also, if you want to access the values repeatedly, why create an iterator instead of just returning the list? – abarnert Apr 23 '13 at 01:46
  • 2
    Why not use a local variable to capture the last output of the iterable? Then if you don't want to move to the next element you can use the local variable's contents. – Patashu Apr 23 '13 at 01:48
  • 1
    If you say why you need to do this, maybe a better method can be suggested – jamylak Apr 23 '13 at 01:54
  • There is a tool `numpy.nditer` which does exactly what you want and more. See my answer below for demonstration. – Developer Apr 23 '13 at 03:51

3 Answers3

1

You certainly can make a class which will allow you to do this:

from collections import deque

class RepeatableIter(object):
    def __init__(self,iterable):
        self.iter = iter(iterable)
        self.deque = deque([])
    def __iter__(self):
        return self

    #define `next` and `__next__` for forward/backward compatability
    def next(self):
        if self.deque:
            return self.deque.popleft()
        else:
            return next(self.iter)
    __next__ = next

    def requeue(self,what):
        self.deque.append(what)


x = RepeatableIter([1, 2, 3, 4, 5, 6])
count = 0
for i in x:
    print i
    if i == 4 and count == 0:
        count += 1
        x.requeue(i)

The question is really why would you want to?

mgilson
  • 300,191
  • 65
  • 633
  • 696
0

You can use numpy.nditer to build your iterator, then you have many amazing options including the current value.

import numpy

rng = range(100)
itr = numpy.nditer([rng])
print itr.next()          #0
print itr.next()          #1
print itr.next()          #2

print itr.value           #2 : current iterator value
Developer
  • 8,258
  • 8
  • 49
  • 58
0

Adapting the third example from this answer:

class CurrentIterator():

    _sentinal = object()
    _current = _sentinal

    @property
    def current(self):
        if self._current is self._sentinal:
            raise ValueError('No current value')
        return self._current

    def __init__(self, iterable):
        self.it = iter(iterable)

    def __iter__(self):
        return self

    def __next__(self):
        try:
            self._current = current = next(self.it)
        except StopIteration:
            self._current = self._sentinal
            raise
        return current
    next = __next__  # for python2.7 compatibility

Some interesting points:

  • use of _sentinal so an error can be raised if no current value exists
  • use of property so current looks like a simple attribute
  • use of __next__ and next = __next__ for Python 2&3 compatibility
Community
  • 1
  • 1
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
  • I would suggest not using a property here... raising a `ValueError` in a property when it hasn't been set seems funky, (`AttributeError` seems more appropriate), but since it is getting set magically ... Also there doesn't seem to be a lot of reason to allow the user to _set_ the current value. I'd just use `.current()` and maintain the state of `_current` internally. But that's just my 2c. In any event, I think this implementation is probably better than mine -- though the original question I posed to the user is still valid. Why would you want this in the first place :-). – mgilson Mar 25 '16 at 20:25
  • @mgilson: Very good point about the setter; implemented and thanks!. – Ethan Furman Mar 25 '16 at 21:51