0

Hi I am trying to make a function that checks for Palindromes and I thought I could easily use the list.reverse() function but something strange is happening and I was wondering why. Here is my code:

x = list('hey')
x
['h', 'e', 'y']
y = x
y
['h', 'e', 'y']
y.reverse()
y
['y', 'e', 'h']
x
['y', 'e', 'h']

My question is why is it that when I reverse the list y it also reverses the list x?

Ridwan Kazi
  • 83
  • 1
  • 8

3 Answers3

2

x and y are refer to same memory location.

>>> x = [1,2,3]
>>> id(x)
141910924
>>> y = x
>>> id(y)
141910924
>>> z = list(x)
>>> id(z)
141676844
>>> x.append(10)
>>> x
[1, 2, 3, 10]
>>> y
[1, 2, 3, 10]
>>> z
[1, 2, 3]

use copy and deepcopy when we want to assign list values to other variables e.g.

>>> import copy
>>> x = [1,2,3, [4,5]]
>>> y = copy.copy(x)
>>> id(x)
141913324
>>> id(y)
139369964
>>> x.append(10)
>>> x
[1, 2, 3, [4, 5], 10]
>>> y
[1, 2, 3, [4, 5]]
>>> x[3].append(20)
>>> x
[1, 2, 3, [4, 5, 20], 10]
>>> y
[1, 2, 3, [4, 5, 20]]
>>> z = copy.deepcopy(x)
>>> z
[1, 2, 3, [4, 5, 20], 10]
>>> x[3].append(50)
>>> x
[1, 2, 3, [4, 5, 20, 50], 10]
>>> z
[1, 2, 3, [4, 5, 20], 10]
>>> 
Vivek Sable
  • 9,938
  • 3
  • 40
  • 56
  • 1
    and the `reverse()` method mutates the list directly – Niklas B. Feb 16 '15 at 16:17
  • adding on to it, you can use the `is` command to verify that it is indeed the same thing, `x=[1,2,3]` `y=[1,2,3]` `x is y` (this is false), `z=x` `z is x` (this is true) – TehTris Feb 16 '15 at 16:19
1

Copy x by value instead of by reference

x = list('hey')
x
['h', 'e', 'y']
y = list(x)
y
['h', 'e', 'y']
y.reverse()
y
['y', 'e', 'h']
x
['h', 'e', 'y']
SomethingSomething
  • 11,491
  • 17
  • 68
  • 126
-2

As Vivek has said, y points to the same location as x. To get around this, use deepcopy from the copy module:

import copy
x = list('hey')
y = copy.deepcopy(x)

This will ensure they point to separate locations and are independent.

To those who think deepcopy is a bad idea, I have to strongly disagree - consider this code:

x = [45, 54]
y = [x, 56]
z = y[::]
print z
x[0] = 1
print z

The output is:

[[45, 54], 56]
[[1, 54], 56]

because the shallow copy returns references to the elements of the list where possible. I am merely trying to teach the OP a generic method to create a completely independent copy - regardless of the type of object they are trying to copy.

Even self referring objects are handled by deepcopy:

>>> a = [2]
>>> a.append(a)
>>> a
[2, [...]]
>>> import copy
>>> b = copy.deepcopy(a)
>>> b
[2, [...]]
texasflood
  • 1,571
  • 1
  • 13
  • 22
  • Actually you only need a shallow copy, such as `[::]` or just by using `reversed` – Niklas B. Feb 16 '15 at 16:21
  • 1
  • Yes, in this simple example where the elements are all integers, `deepcopy` is unnecessary. But if you have a list with an embedded list, you need deepcopy. – texasflood Feb 16 '15 at 16:29
  • Hey Niklas could you show me how to use those suggestions? I am pretty new to python and dont really know how to use extended slices. – Ridwan Kazi Feb 16 '15 at 16:30
  • @AnttiHaapala Wow, you are just plain wrong. In fact, I would say most of the time, deepcopy is exactly what you need when you want independence. There are many cases where deepcopy is the only solution, aside from manually shallow copying the internal objects. Sure, sometimes it is unnecessary (eg for the OPs simple example). – texasflood Feb 16 '15 at 16:41