Home > Net >  why am I getting this error? TypeError: iter() returned non-iterator of type 'NoneType'
why am I getting this error? TypeError: iter() returned non-iterator of type 'NoneType'

Time:05-12

I'm trying to learn the __iter__ method and this is the error I'm getting:

print(i for i in my_iter)
TypeError: iter() returned non-iterator of type 'NoneType'

My code is as follows:

class IterMethod:
    def __init__(self, last_elem):
        pass

    def __iter__(self):
        i = 5
        while i <= 50:
            print(f"this is {i}")
            i = i   10
    
my_iter = IterMethod(60)

print(i for i in my_iter)

Can you please explain why? Thanks!

CodePudding user response:

(My apologies, in my haste to provide an answer, I hadn't explained why there was an error. This edit is to include the explanation.)

Explanation:

The TypeError: iter() returned non-iterator of type 'NoneType' means that __iter__() wasn't returning any values (by default, this means it's None for "No return value" (In this particular case)). (Confusing, I know as that means it's technically returning None.)

__iter__ must return a value each time it 'generates' a value from within the function. If it doesn't return a value, you get the error.

Please note that when I say return a value, you don't use return. In the case of iter (which is basically a generator function), you need to use yield. If you're confused with this, please read up on what generators are. i.e. at https://www.geeksforgeeks.org/generators-in-python/ (for example, and not affiliated to this link).

So...

Two issues plus one change (as suggested by @DanielWalker):

  1. You could make it simpler by changing:
   i = i   10

to

   i  = 10
  1. You need to change your print(i for i in my_iter).

As is this prints the generator signature. What you want is:

   print(list(i for i in my_iter))
  1. You need to have a yield statement in your __iter__ method.

Depending on if you want the i value to be, you have the following options:

class IterMethod:
    def __init__(self, last_elem):
        pass

    def __iter__(self):
        i = 5
        while i <= 50:
            print(f"this is {i}")
            i  = 10
            yield i


my_iter = IterMethod(60)

print(list(i for i in my_iter))

So this will output:

this is 5
this is 15
this is 25
this is 35
this is 45
[15, 25, 35, 45, 55]

Now if you want to yield the i value before the i = i 10,

class IterMethod:
    def __init__(self, last_elem):
        pass

    def __iter__(self):
        i = 5
        while i <= 50:
            print(f"this is {i}")
            yield i
            i  = 10


my_iter = IterMethod(60)

print(list(i for i in my_iter))

This will output:

this is 5
this is 15
this is 25
this is 35
this is 45
[5, 15, 25, 35, 45]
  • Related