Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Multi-class iterator
#1
Hi and Happy New Year!

I am studying Reuven Lerner's book Python Workout, now at chapter 10, Iterators and Generators.

I don't know about classes, I never wrote any, except the examples in this book.

First, I have this, class:

class MyEnumerate():
    # Initializes MyEnumerate with an iterable argument, “data”
    def __init__(self, data):
        # Stores “data” on the object as self.data
        self.data = data
        # Initializes self.index with 0
        self.index = 0

    def __iter__(self):
        # Because our object will be its own iterator, returns self
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            # Are we at the end of the data? If so, then raises StopIteration
            raise StopIteration
        # Sets the value to be a tuple, with the index and value
        value = (self.index, self.data[self.index])
        # increment the index in the function above
        self.index += 1
        # return the value tuple
        return value
Then this code works fine:

for index, letter in MyEnumerate('abc'):
    print(f'{index} : {letter}')
Now, the exercise is make a new class, let's call it MyEnumerate2() and a helper class, MyEnumerateIterator().
The helper class should do the indexing, such that this code below will print 2 times. (using MyEnumerate, it only prints 1 time, because the index is already at max):

e = MyEnumerate2('abc')

print('** A **')

for index, one_item in e:
    print(f'{index}: {one_item}')
    
print('** B **')

for index, one_item in e:
    print(f'{index}: {one_item}') 


Quote:Rewrite MyEnumerate such that it uses a helper class ( MyEnumerateIterator ), as described in the “Discussion” section. In the end, MyEnumerate will have the __iter__ method that returns a new instance of MyEnumerateIterator , and the helper class will implement __next__ . It should work the same way, but will also produce results if we iterate over it twice in a row.

Reuven Lerner says, I should put:

def __iter__(self):
    return MyEnumerateIterator(self.data)
in MyEnumerate2()

I have tried various things, but my lack of understanding of classes prevents me from getting a working solution.

Can anyone please point me in the right direction??

I think it just needs a small change in MyEnumerate(), but I am not getting there!
Reply
#2
Your __iter__ object has an error. It does properly set things up for iteration.
def __iter__(self):
    self.index = 0
    return self
Without this change you can only iterate through a MyEnumerate object once. It sounds like the purpose of the assignment is to fix this problem without making any changes to the MyEnumerator code.
class MyEnumerate():
    def __init__(self, data):
        self.data = data
        self.index = 0
 
    def __iter__(self):
        return self
     
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = (self.index, self.data[self.index])
        self.index += 1
        return value

class MyEnumerateFixInit(MyEnumerate):
    def __iter__(self):
        self.index = 0
        return self

class MyEnumerateIterator():
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = (self.index, self.data[self.index])
        self.index += 1
        return value

class MyEnumerate2(MyEnumerate):
    def __iter__(self):
        return MyEnumerateIterator(self.data)

def test_iterator(cls):
    print('\n\nTesting iterator for', cls.__name__)
    obj = cls(list(range(5)))
    for t in obj:
        pass
    for t in obj:
        print(t)

test_iterator(MyEnumerate)
test_iterator(MyEnumerateEasyFix)
test_iterator(MyEnumerate2)
If you run the code above you will see that MyEnumerate can only iterate through data 1 time, but MyEnumerateFixIter and MyEnumerate
I would fix the iterator problem by fixing the MyEnumerate class. If I couldn't get hold of the code I would subclass and fix the __iter__ method. If I couldn't do that I would make a custom iterator class like is done with MyEnumerate2 and MyEnmerateIterator.
Pedroski55 likes this post
Reply
#3
Thank you very much! Works like a charm!

I set: e = MyEnumerate2('cdef') and it prints any number of times.

(slight typo in # test_iterator(MyEnumerateEasyFix) should be test_iterator(MyEnumerateFixInit) I think)

I still need time to absorb class.

I only do simple things with Python. I can't see any application for defining classes in what I do, but I will study them some more.

Thanks again!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  prime numbers with iterator and generator cametan_001 8 1,862 Dec-17-2022, 02:41 PM
Last Post: cametan_001
  resetting an iterator to full Skaperen 7 6,956 Feb-20-2022, 11:11 PM
Last Post: Skaperen
  popping an iterator Skaperen 11 3,684 Oct-03-2021, 05:08 PM
Last Post: Skaperen
  q re glob.iglob iterator and close jimr 2 2,224 Aug-23-2021, 10:14 PM
Last Post: perfringo
  Problem with an iterator grimm1111 9 4,287 Feb-06-2021, 09:22 PM
Last Post: grimm1111
  Applying Multi-Class Classification instead of binary classification alex80 1 1,500 Sep-18-2020, 07:39 AM
Last Post: alex80
  is a str object a valid iterator? Skaperen 6 5,623 Jan-27-2020, 08:44 PM
Last Post: Skaperen
  discard one from an iterator Skaperen 1 1,985 Dec-29-2019, 11:02 PM
Last Post: ichabod801
  how do i pass duplicates in my range iterator? pseudo 3 2,352 Dec-18-2019, 03:01 PM
Last Post: ichabod801
  looking for a sprcil iterator Skaperen 7 3,336 Jun-13-2019, 01:40 AM
Last Post: Clunk_Head

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020