Reputation: 33
I have iterator object which I want to convert it into list but it behaving very strange.
Here is an example. This is not original code but only for generating the exact same behavior to understand the problem.
class Sqrt:
def __init__(self, num):
self.original = num
self.sqrt = num * 2
class Math:
def set_value(self, num):
self.num = num
return self
def value(self):
return Sqrt(self.num)
class Counting:
def __init__(self):
self.num = 0
self.math = Math()
def __iter__(self):
return self
def __next__(self):
num = self.num
self.num += 1
if num <= 5:
m = self.math.set_value(num)
return m
raise StopIteration
c = Counting()
l = list(c)
for n in l:
print(n.value().original) # This will return 5 every time
if you use it in for
loop then everything is working fine.
for n in c:
print(n.value().original) # it work perfect
Upvotes: 3
Views: 1531
Reputation: 20530
This is a somewhat common issue; you will not be the first to trip across it.
m
each time you call __next__()
l = list(c)
, you have five copies of the same Math object.__next__()
m = self.math.set_value(num)
to m = Math().set_value(num)
You might also try adding print(l)
to your code. You should get the same object id repeated, like:
[<__main__.Math object at 0x7f99100d9748>, <__main__.Math object at 0x7f99100d9748>, <__main__.Math object at 0x7f99100d9748>, <__main__.Math object at 0x7f99100d9748>, <__main__.Math object at 0x7f99100d9748>, <__main__.Math object at 0x7f99100d9748>]
It can be confusing. Here is another example:
>>> a = [5]
>>> b = [a,a,a]
>>> b
[[5], [5], [5]]
>>> b[0][0]=9
>>> b
[[9], [9], [9]]
Upvotes: 0
Reputation: 23
Using list comprehension instead of for loop will return a list.
c = Counting()
out_list = [n.value().original for n in c]
print(out_list)
Output:
[0, 1, 2, 3, 4, 5]
Upvotes: 1
Reputation: 251
The lines
def __next__(self):
num = self.num
self.num += 1
if num <= 5:
m = self.math.set_value(num)
return m
raise StopIteration
Update and return the same object each time. In the block
c = Counting()
l = list(c)
for n in list:
print(n.value().original)
you first call next()
five times, updating c.math.original each time; you then print that value five times, once for each copy in the list. When you run
for n in c:
print(n.value().original)
you interleave calling c.next()
and printing the value; you're still updating c.math.original
each time, but now you're printing between updates, so you see the numbers 1 through 5.
To see what's going on, try running
l = list(c)
for n in l:
print(id(n.value()))
and
for n in c:
print(id(n.value()))
and you'll see that in each case the id of each object is the same (i.e. they refer to the same object).
Upvotes: 0