Deleting a list after creating an iterator object from it
<p>I am trying to understand the concept of iterators in python and tried this in Python 3.5.2.</p>

<pre><code>x = list(range(1000))    # size of x is 9112 bytes
y = iter(x)              # size of y is 56 bytes
del x
x = list(y)              # size of x is again 9112 bytes
</code></pre>

<p>How does the iterator store the information about the sequence it has to generate?</p>

<p>It does not contain all the elements but even after deleting the original list we are still able to reproduce the original list from the iterator?</p>

<p>If it does not contain all the elements how does it know which is the next element even after deleting <code>x</code>?</p>

<p>Because iterators have enough details stored in them to enable them generate the next element of a sequence without having that "next element" in memory.</p>

<p>To understand what is going on let's create our own fake iterator</p>

<pre><code>class Fakeiterator:
    def __init__(self, range_list):
        self.current = range_list[0]
        self.high = range_list[-1]

    def __iter__(self):
        return self

    def __next__(self):
        if self.current &gt; self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1
</code></pre>

<p>In our <code>__init__</code> method we've stored enough details (the start point and end point of our iterator) to enable us generate the next element without actually having it in memory. As far as we have this information, even though we're given a list containing 2000 elements we just need to know the start and end point</p>

<p>in our <code>__next__</code> method anytime we ask for the next element in our iterator, The iterator simply increments the current counter and return it back to us.</p>

<p>Lets test our iterator:</p>

<pre><code>&gt;&gt;&gt; x = list(range(5))
&gt;&gt;&gt; y = Fakeiterator(x)
&gt;&gt;&gt; del x
&gt;&gt;&gt; list(y)
[0, 1, 2, 3, 4]
&gt;&gt;&gt;
</code></pre>

<p>The <code>list</code> constructor repeatedly calls <code>__next__</code> until <code>StopIteration</code> is raised by our iterator and that's at the point where the current element is higher than the maximum element we stored at the creation of the iterator.</p>

<p>But in your case calling <code>iter(x)</code> on a list, returns a <code>list_iterator</code> object that <strong>STORES</strong> x internally. <code>x</code> is still stored but not with the name <code>x</code> anymore.</p>

<p>On why <code>getsizeof</code> returns a lower size which as you expected is supposed to be greater or at least equal to the size of the original list. from the docs</p>

<blockquote>
  <p>sys.getsizeof(object[, default]) Return the size of an object in
  bytes. The object can be any type of object. All built-in objects will
  return correct results, but this does not have to hold true for
  third-party extensions as it is implementation specific.</p>
  
  <p><strong>Only the memory consumption directly attributed to the object is
  accounted for, not the memory consumption of objects it refers to.</strong></p>
  
  <p>If given, default will be returned if the object does not provide
  means to retrieve the size. Otherwise a TypeError will be raised.</p>
  
  <p>getsizeof() calls the objectâs <strong>sizeof</strong> method and adds an
  additional garbage collector overhead if the object is managed by the
  garbage collector.</p>
</blockquote>

<p>To demonstrate that let's write a quick script</p>

<pre><code>import sys

x = [1, 2, 3]

print(sys.getsizeof(x))

class storex():
    def __init__(self, param):
        self.param = param

y = storex(x)

print(sys.getsizeof(y))
print(y.param, sys.getsizeof(y.param))
</code></pre>

<p>When you run the script. this is the output (on my machine, but it should be the same with yours)</p>

<pre><code>88
56
[1, 2, 3] 88
</code></pre>

<p>even though the list <code>[1, 2, 2]</code> is 88 bytes long, when we store it as an attribute of <code>storex</code> it doesn't automatically make <code>storex</code> become larger than it. because <code>storex</code> refers to it. it's not part of <code>storex</code> directly</p>

<p>But on printing the size of <code>y.param</code>, we can see that it's still the same size as the original <code>[1, 2, 3]</code> list</p>

<p>Also <code>del</code> doesn't delete the object from memory, it simply unbinds the name <code>x</code> so x won't refer to any object in memory. the value of x will only be discarded (garbage collected) when there is no reference to it again</p>

<p>Here is a demonstration of what i mean</p>

<pre><code>&gt;&gt;&gt; x = [1,2,3]
&gt;&gt;&gt; class y: pass
... 
&gt;&gt;&gt; y.x = x
&gt;&gt;&gt; id(x), id(y.x)
(140177507371016, 140177507371016)
&gt;&gt;&gt; del x
&gt;&gt;&gt; id(y.x)
140177507371016
&gt;&gt;&gt; x
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in &lt;module&gt;
NameError: name 'x' is not defined
&gt;&gt;&gt;
</code></pre>

<p>deleting <code>x</code> doesn't automatically delete <code>[1,2,3]</code> which <code>y.x</code> points to, even though their id's show that they both pointed to the same object in memory.</p>

python iterator iterable