简体   繁体   中英

Convert iterator into List in python

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

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 (ie they refer to the same object).

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]

This is a somewhat common issue; you will not be the first to trip across it.

  • You return the same object m each time you call __next__()
  • When you do l = list(c) , you have five copies of the same Math object.
  • The value in that object is 5, which you set on the last call to __next__()
  • When you print in a for loop, you are still reusing the same math object, but you print the value before it changes for the next iteration.
  • If you want to fix this, you could change 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]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM