In [1]:
from __future__ import print_function

In [2]:
class my_range():
    def __init__(self, n):
        self.n = n
        self.i = 0

    def __next__(self):
        if self.i < self.n:
            self.i += 1
            return self.i - 1
        else:
            raise StopIteration

In [3]:
for i in my_range(3):
    print(i, i*i)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-abd021d29024> in <module>()
----> 1 for i in my_range(3):
      2     print(i, i*i)

TypeError: 'my_range' object is not iterable

In [4]:
for i in iter(my_range(3)):
    print(i, i*i)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-cd985f72292f> in <module>()
----> 1 for i in iter(my_range(3)):
      2     print(i, i*i)

TypeError: 'my_range' object is not iterable

In [5]:
f = my_range(3)

In [6]:
f()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-0ec059b9bfe1> in <module>()
----> 1 f()

TypeError: 'my_range' object is not callable

In [7]:
next(f)


Out[7]:
0

In [8]:
next(f)


Out[8]:
1

In [9]:
next(f)


Out[9]:
2

In [10]:
next(f)


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-10-468f0afdf1b9> in <module>()
----> 1 next(f)

<ipython-input-2-09a747670c9e> in __next__(self)
      9             return self.i - 1
     10         else:
---> 11             raise StopIteration

StopIteration: 

In [11]:
class my_range():
    def __init__(self, n):
        self.n = n
        self.i = 0
        
    def __iter__(self):
        return self

    def __next__(self):
        i = self.i
        if i < self.n:
            self.i += 1
            return i
        else:
            raise StopIteration

In [12]:
for i in my_range(3):
    print(i, i*i)


0 0
1 1
2 4

In [13]:
f = my_range(3)

In [14]:
f()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-0ec059b9bfe1> in <module>()
----> 1 f()

TypeError: 'my_range' object is not callable

In [15]:
next(f)


Out[15]:
0

In [16]:
next(f)


Out[16]:
1

In [17]:
next(f)


Out[17]:
2

In [18]:
next(f)


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-18-468f0afdf1b9> in <module>()
----> 1 next(f)

<ipython-input-11-486dfc1f7af9> in __next__(self)
     13             return i
     14         else:
---> 15             raise StopIteration

StopIteration: 

In [19]:
f = iter(my_range(3))

In [20]:
f()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-0ec059b9bfe1> in <module>()
----> 1 f()

TypeError: 'my_range' object is not callable

In [21]:
next(f)


Out[21]:
0

In [22]:
next(f)


Out[22]:
1

In [23]:
next(f)


Out[23]:
2

In [24]:
next(f)


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-24-468f0afdf1b9> in <module>()
----> 1 next(f)

<ipython-input-11-486dfc1f7af9> in __next__(self)
     13             return i
     14         else:
---> 15             raise StopIteration

StopIteration: 

In [25]:
def my_range(n):
    i = 0
    def gimme():
        if i < n:
            i += 1
            return i - 1
        else:
            raise StopIteration
    return gimme

In [26]:
f = my_range(3)

In [27]:
f()


---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-27-0ec059b9bfe1> in <module>()
----> 1 f()

<ipython-input-25-0c62601254db> in gimme()
      2     i = 0
      3     def gimme():
----> 4         if i < n:
      5             i += 1
      6             return i - 1

UnboundLocalError: local variable 'i' referenced before assignment

In [28]:
def my_range(n):
    i = 0
    def gimme():
        nonlocal i
        if i < n:
            i += 1
            return i - 1
        else:
            raise StopIteration
    return gimme

In [29]:
for i in my_range(3):
    print(i, i*i)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-29-abd021d29024> in <module>()
----> 1 for i in my_range(3):
      2     print(i, i*i)

TypeError: 'function' object is not iterable

In [30]:
f = my_range(3)

In [31]:
f()


Out[31]:
0

In [32]:
f()


Out[32]:
1

In [33]:
f()


Out[33]:
2

In [34]:
f()


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-34-0ec059b9bfe1> in <module>()
----> 1 f()

<ipython-input-28-ed8a59c801ef> in gimme()
      7             return i - 1
      8         else:
----> 9             raise StopIteration
     10     return gimme

StopIteration: 

In [35]:
def my_range(n):
    def gimme(i=0):
        if i < n:
            i += 1
            return i - 1
        else:
            raise StopIteration
    return gimme

In [36]:
f = my_range(3)

In [37]:
f()


Out[37]:
0

In [38]:
f()


Out[38]:
0

In [39]:
def my_range(n):
    i = 0
    def gimme(i=i):
        if i < n:
            i += 1
            return i - 1
        else:
            raise StopIteration
    return gimme

In [40]:
f = my_range(3)

In [41]:
f()


Out[41]:
0

In [42]:
f()


Out[42]:
0

In [43]:
def my_range(n):
    x = [0]
    def gimme():
        if x[0] < n:
            x[0] += 1
            return x[0] - 1
        else:
            raise StopIteration
    return gimme

In [44]:
f = my_range(3)

In [45]:
f()


Out[45]:
0

In [46]:
f()


Out[46]:
1

In [47]:
f()


Out[47]:
2

In [48]:
f()


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-48-0ec059b9bfe1> in <module>()
----> 1 f()

<ipython-input-43-36b843e7d7f1> in gimme()
      6             return x[0] - 1
      7         else:
----> 8             raise StopIteration
      9     return gimme

StopIteration: 

In [49]:
def my_range(n):
    i = 0
    while i < n:
        yield i
        i += 1

In [50]:
f = my_range(3)

In [51]:
f()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-51-0ec059b9bfe1> in <module>()
----> 1 f()

TypeError: 'generator' object is not callable

In [52]:
next(f)


Out[52]:
0

In [53]:
next(f)


Out[53]:
1

In [54]:
next(f)


Out[54]:
2

In [55]:
next(f)


---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-55-468f0afdf1b9> in <module>()
----> 1 next(f)

StopIteration: