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):
- You could make it simpler by changing:
i = i 10
to
i = 10
- 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))
- 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]