0
x=5
y=x
x=7
# Changing the value of x does not effect the value of y

As a simple example both x&y have different memory location so changing one does not effect other

But in the code below next(y) is giving 4 why? According to my logic it must be 1 where I am going wrong

a=[1,2,3,4,5,6,7,8,9,10]
x=iter(a)
y=x

print(next(x))
print(next(x))
print(next(x))

print(next(y))

  • 6
    You are mistaken. ```y = x``` will assign the reference to ```y``` which points to the **same** object in the memory –  Aug 30 '21 at 12:04
  • If you need to duplicate iterable use https://docs.python.org/3/library/itertools.html#itertools.tee – Ruslan Tushov Aug 30 '21 at 12:06
  • That means the next() function changes are reflected on the object iter(a) @Sujay – Vinayak Bansal Aug 30 '21 at 12:08
  • 2
    Assignment never copies data in Python. – timgeb Aug 30 '21 at 12:09
  • 1
    Does this answer your question? [Are python variables pointers? or else what are they?](https://stackoverflow.com/questions/13530998/are-python-variables-pointers-or-else-what-are-they) – MisterMiyagi Aug 30 '21 at 12:11
  • If you assign a new value to `x` like you did in your first example - `x = iter(a); y = x; x = iter(a)` - and then do your `next`s, your second code will behave as you expected. – molbdnilo Aug 30 '21 at 12:20
  • 1
    "As a simple example both x&y have different memory location" No, they do not. Both `x` and `y` are *referring to the same object*. However, `x=7` **does not mutate whatever object `x` was referring to*, it just re-assigns the name `x` to a new object – juanpa.arrivillaga Aug 30 '21 at 12:28
  • 1
    x is just a generator object, and y is x, so whenevr next of x is called, value of the next(x) updated both in x and y – sahasrara62 Aug 30 '21 at 12:45

2 Answers2

2

Doing y=x creates named reference y that basically points to the same memory location as pointed by variable x, you can use id (which gives memory location representation) builtin to verify it:

>>> a=[1,2,3,4,5,6,7,8,9,10]
>>> x=iter(a)
>>> y=x
>>> id(x)
1714277910984
>>> id(y)
1714277910984

If you want a copy of the iterator x, you can use deepcopy function from copy module:

>>> from copy import deepcopy
>>> y = deepcopy(x)
>>> id(x)
1714277910984
>>> id(y)
1714135198792

Now x and y are two different iterators:

>>> next(x)
1
>>> next(y)
1
>>> next(x)
2
>>> next(y)
2
ThePyGuy
  • 17,779
  • 5
  • 18
  • 45
  • Note, a regular `copy.copy` should work. – juanpa.arrivillaga Aug 30 '21 at 12:52
  • It's probably worth pointing out that not every iterator can be meaningfully copied. For example, copying a ``map`` iterator will just return the original. – MisterMiyagi Aug 30 '21 at 12:52
  • @juanpa.arrivillaga *Might* even be [preferable](https://tio.run/##rY7BCsIwDIbveYqAh7UQZO3UTcEnEQ9DK/awNdQe2qev3XAiHsWcku/nDx@ncHdj07HP@ebdgBfHCe3Azge8GsPTTTMFYG/HIKoFHyoJPR7xpEhTQxva0o5a6mhPqj5DLJENxoteQir7UhOx1NbsWNTy9XI0MRQscZoVzvCB@jNN36l6@/zg8kcPDTk/AQ). – no comment Aug 30 '21 at 19:18
  • @don'ttalkjustcode yeah, I guess it depends on whether you need deep copy semantics, or if a shallow copy is necessary (or merely sufficient)\ – juanpa.arrivillaga Aug 30 '21 at 19:23
  • @MisterMiyagi Actually it [seems to](https://tio.run/##VYw7DsIwEAX7PcWWtvQKQviEgpOgFBY4IhK2V2YL@/SOKUCinDeaJ1WfKY6T5NaWnALfk1Reg6Ss/PBePkzk@Mq3AXuMOOCIE86YcMGwm6l0FZyY5ZWcgp2l2pdvaoolyWtU01/f/KPoi3b3h9Xa1jY) give a separate independent iterator. – no comment Aug 30 '21 at 19:25
  • @don'ttalkjustcode Try it with just a ``copy.copy`` instead. – MisterMiyagi Aug 30 '21 at 19:46
  • @MisterMiyagi Just means we need to use the appropriate copying method for a meaningful copy :-). And still a [new object](https://tio.run/##HYwxDoMwEAT7e8WVtrQF4CRAwUtQCgsJBSnmTsaF/XrHoVvNaFZL@sjpJo217lECb6KFj6AS072JPC@89hjg8MATL4yYMKPv3pSbCl7N/hWfwN5SaeSfmWxJ43Em094uzrbWHw), not the original. – no comment Aug 30 '21 at 19:55
1

In the first example

x=5
y=x
x=7

After the second line, x and y point to the same object, that is 5. When you change x, y stays 5 because you didn't change the object 5 itself, but you just changed the location to which x points to. However, in the second example,

a=[1,2,3,4,5,6,7,8,9,10]
x=iter(a)
y=x

print(next(x))
print(next(x))
print(next(x))

print(next(y))

x and y still point to the same location. But when you call the next method, you are changing the object at that location, you are not making a new object at a different location.