Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python iterators. Initialize state variables in __init__ or __iter__?

I'm fairly new to Python and was just looking at some examples of defining iterator objects.

The example I looked at was :

class fibit:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):       
        self.max = max

   def __iter__(self):
        self.a = 0
        self.b = 1
        return self

   def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

But if I move the initialization of self.a and self.b from iter to init it seems (to my simple understanding) to work exactly the same way.

class fibit:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.a = 0
        self.b = 1        
        self.max = max

   def __iter__(self):
        return self

   def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

So which one is the recommended way to do this?

Thanks. :)

like image 454
Stuart Avatar asked Feb 15 '13 17:02

Stuart


1 Answers

Initialization should be done in __init__. That's why it's there.

Iterator objects in Python are canonically "use once" - once you've iterated through an iterator, it's not expected that you'll be able to iterate through it again.

Thus, it makes no sense to re-initialize the values if you try to iterate over the object again. To illustrate this, I've extended your code a bit:

class fibit_iter:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.max = max

    def __iter__(self):
        self.a = 0
        self.b = 1
        return self

    def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

class fibit_init:  # iterate through fibonacci sequence from 0,1...n<=max
    def __init__(self, max):
        self.a = 0
        self.b = 1
        self.max = max

    def __iter__(self):
        return self

    def next(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

iter_iter = fibit_iter(10)
iter_init = fibit_init(10)

print "iter_iter"

for item in iter_iter:
    print item
    break

for item in iter_iter:
    print item
    break

print "iter_init"

for item in iter_init:
    print item
    break

for item in iter_init:
    print item
    break

Essentially, I create an object from your init version, and an object from your iter version. Then I try partial iterating over both of them twice. Notice how you get different results:

iter_iter
0
0
iter_init
0
1
like image 158
Amber Avatar answered Oct 03 '22 05:10

Amber