mikeizbicki / cmc-csci046

CMC's Data Structures and Algorithms Course Materials
53 stars 153 forks source link

Question about magic functions #272

Closed Michaelhess17 closed 3 years ago

Michaelhess17 commented 3 years ago

Hello! In other contexts, I have seen people define the __iter__method to simply return self, and then they implement the __next__ method within the same class as the rest of the code (without needing to define a separate Iter Class). Is there a reason to prefer creating a separate class, or is this way of setting up the iter/next methods acceptable?

mikeizbicki commented 3 years ago

It's essentially not possible to do things correctly using the 1 class method even though that's what most tutorials try to teach. If that were the way it should really be done, then there'd be no point in having the __iter__ method to begin with, since it would always do the same thing.

Consider the following example:

class mylist:
    def __init__(self, xs):
        self.xs = xs

    def __iter__(self):
        self.i = 0
        return self

    def __next__(self):
        self.i += 1
        if self.i > len(self.xs):
            raise StopIteration
        return self.xs[self.i-1]

It's a simple wrapper around the list class that redefines the __iter__ and __next__ magic methods using the 1 class approach that you suggest.

This works fine on single for loops:

xs = mylist([1,2,3,4,5])
for x in xs:
    print("x=",x)

produces

x= 1
x= 2
x= 3
x= 4
x= 5

But it breaks on a nested for loop:

for x1 in xs:
    for x2 in xs:
        print("x1=", x1, "  x2=", x2)

results in

x1= 1   x2= 1
x1= 1   x2= 2
x1= 1   x2= 3
x1= 1   x2= 4
x1= 1   x2= 5

The problem is that the state between the two for loops is not adequately separated from each other, and so both loops use the same counter i, resulting in the outer loop not actually looping.

Of course, it's not actually impossible to use only a single class, it's just much more complicated to do it correctly than to just create 2 separate classes.

Michaelhess17 commented 3 years ago

okay makes sense! thanks!