Implement a range behaviour in Python using iterators I've been assigned the following Python homework:

Implement myrange that acts like range using iterators. Define a function myrangeand  define a class MyRange.

We've just seen iterators, so I think I'm asked to use them. I am not required to write a sophisticated code, but only something that allows the range-for loop syntax.
Professor said that, roughly, an iterator is an object for which the dunder method __next__ is provided. I've seen there are similar questions here. However, none of them is defining the __next__ method in a class.

So, here's what I did: first I implemented MyRange class and then my range. After that, I did two tests.
Question: It works, but I'd like to be sure from you if I solved correctly the question, I mean, if this is what I was supposed to do :-) As I said, I've just seen what is an iterator.
class MyRange():
    
    def __init__(self,data):
        self.data = data
        self.check()
        self.index = -1
        
    def check(self):
        assert len(self.data)&gt;0, &quot;Not enough data&quot;
            
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index == len(self.data)-1:
            raise StopIteration
        self.index= self.index+1
        return self.data[self.index]

        




def my_range(*args):
    return MyRange((args))

print(&quot;Tests using MyRange class \n&quot;)

for i in MyRange((1,2,3,4)):
    print(i)    


print(&quot;Tests with range for loop \n&quot;)
for i in my_range(1,2,3,4,5,&quot;Hello&quot;):
    print(i)


r = MyRange((1,2,3,4,&quot;Last Value&quot;))
print(next(r))
print(next(r)) 
print(next(r))
print(next(r)) 
print(next(r)) 
print(next(r)) 

I'll show here the output, which seems the correct one:
1
2
3
4
Tests with range for loop 

1
2
3
4
5
Hello
1
2
3
4
Last Value
Traceback (most recent call last):
  File &quot;Untitled3.py&quot;, line 45, in &lt;module&gt;
    print(next(r)) #&lt;-- Raises StopIteration
  File &quot;Untitled3.py&quot;, line 16, in __next__
    raise StopIteration
StopIteration
You have an iterator
Your code implements an iterator, you are right. You have defined a __next__ method and it works well.
I would tweak your code slightly, though:

remove the check because iterators can be empty and that is okay;
fix minor spacing issues around operators, etc;
use augmented assignment to increment;
change order of statements in __next__ to be more idiomatic.

All in all, MyRange would end up looking like this:
class MyRange():
    def __init__(self,data):
        self.data = data
        self.index = -1
            
    def __iter__(self):
        return self
    
    def __next__(self):
        self.index += 1
        if self.index == len(self.data):
            raise StopIteration
        return self.data[self.index]

In particular, the changes to __next__ are because you start by setting self.index to the value of the index you would like to read. Then, just before reading the value from data, you ensure you can actually use that index and raise StopIteration if you can't.
range is not any iterator
However, the &quot;problem statement&quot; says to implement an iterator that behaves like range, and as brought to your attention in the comments, range is a very specific iterator that can take up to 3 arguments: start, stop, and step.
Take a look at the docs for the range function here.
Having said that, solving this &quot;issue&quot; does not need to be very difficult.
You could do something as simple as having my_range take the three arguments,
generate the data you need, and then feed it into MyRange to iterate, but that seems like a waste.
What I think is more or less the intended approach, is to define MyRange to expect the start, stop, and step values, and the my_range function is what the user calls, which then fills in the start, stop, and step values that are used by default and calls MyRange.
E.g.,

my_range(10) would call MyRange(0, 10, 1);
my_range(4, 12) would call MyRange(4, 12, 1);
my_range(0, 13, -3) would call MyRange(0, 13, -3).

(In the examples above, I assumed you changed MyRange to do what I described.)
Therefore, just for the sake of clarity: what would be happening is that the __next__ method would use the three arguments start, stop, and step (and possibly other auxiliary variables you create) to compute the successive values, instead of generating all of them at once and then returning one by one.