The reason is that iter(my_list)
and next(my_iter)
are different objects. my_iter
is the iterator itself, whereas next(my_iter)
is a value yielded/produced by the iterator.
x = [1,2,3,4,5]
my_iter = iter(x)
type(my_iter)
# <class 'list_iterator'>
# This is a different object
type(next(my_iter))
# <class 'int'>
Moreover, the id
of each object yielded by next(my_iter)
is the id of the corresponding value in the list
id(next(my_iter))
4405200304
id(x[0])
4405200304
The way for id(b)
to be the same as id(my_iter)
is if b
is my_iter
, thus they are names referring to the same object:
x = [1,2,3,4,5]
my_iter = iter(x)
# b is now the same as my_iter, they refer to the same object
b = my_iter
id(my_iter)
4413711920
id(b)
4413711920
It's easy to get caught up in id
representing memory addresses, it's best to try to ignore that and think of how names are bound to objects in python. I have fallen into this trap many times, as shown in the comments thread of this question, where chepner and juanpa give really good explanations of how this works in python (while dealing with my ignorance, at that)
An instance variable in a class is also a different object than the class. A reference to it is held in the instance dictionary, but again, the class and instance variable are two completely different objects.
As an example:
a = 1
x = list(range(5))
id(a) == id(x[1])
# True
The memory management under the hood of python is different. Even though I have instantiated a
and x
separately, a
and x[1]
share the same id
because the memory for those objects was re-used. x[1]
is another name/variable bound to the value 1
, just like a
is. This even happens with instance vars:
class Test:
def __init__(self):
self.a = 5
x = 5
c = Test()
id(x)==id(c.a)
True