4

I know when send a list as parameter to a function, the changes in function will change the list, for example:

p=[[3, 4], [2, 3]]
node=[5,3]

def foo(node, p_as_list):
    p_as_list.append(node)


foo(node, p)
print(p) #p changes

to stop the changes I used copy():

p=[[3, 4], [2, 3]]
node=[5,3]

def foo(node, p_as_list):
    p_as_list.append(node)

#this line
foo(node, p.copy())
print(p) # without changes

but if I change the function like this:

p=[[3, 4], [2, 3]]
node=[5,3]

def foo(node, p_as_list):
    #this line
    p_as_list=p_as_list[-1]
    p_as_list.append(node)

foo(node, p.copy())
print(p) 

p will change again, I cant understand why this happen ?

pd shah
  • 1,346
  • 2
  • 14
  • 26
  • 5
    It's because you're doing a shallow copy, instead of a deep one. You're copying references to those inner lists, which are still modified. See [What is the difference between a deep copy and a shallow copy?](http://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy) – SuperBiasedMan Dec 19 '16 at 12:06
  • I need a memory efficient way for pass the list to function and I need to the list not change, is there any better solution? – pd shah Dec 19 '16 at 12:09
  • 2
    I'm not sure of your exact circumstances, but you could try just copying the part/s of the list being modified. For example, if you had done `p_as_list=p_as_list[-1].copy()` the original list would be unchanged and you wouldn't waste memory duplicating every aspect of the original list. You could even remove the `p.copy()` part being passed to the function. – SuperBiasedMan Dec 19 '16 at 12:15

2 Answers2

1

Inserting some debug prints helps to identify the issue:

p=[[3, 4], [2, 3]]
node=[5,3]

def foo(node, p_as_list):
    #this line
    print('p', id(p_as_list))
    p_as_list=p_as_list[-1]
    print('pm1', id(p_as_list))
    p_as_list.append(node)

print('p', id(p))
print('pm1', id(p[-1]))
foo(node, p.copy())
print(p) 

this prints:

p 1872370555144 
pm1 1872370556232
p 1872370108872
pm1 1872370556232
[[3, 4], [2, 3, [5, 3]]]

Note that the id of p[-1] hasn't changed, you operate on the same list. That is because you only create a shallow copy when you use list.copy()!

Instead of copying the whole list I would advise to just copy the parts you modify inside your functions:

p=[[3, 4], [2, 3]]
node=[5,3]

def foo(node, p_as_list):
    #this line
    p_as_list=p_as_list[-1].copy()  # copy here!
    p_as_list.append(node)

foo(node, p)  # don't copy here!
print(p) 
MSeifert
  • 145,886
  • 38
  • 333
  • 352
0

One way to do this is to use deepcopy

Reference library path : https://docs.python.org/2/library/copy.html

import copy

p = [[3, 4], [2, 3]]
node = [5,3]

def foo(node, p_as_list):
    p_as_list = p_as_list[-1]
    p_as_list.append(node)

foo(node, copy.deepcopy(p))

print(p)
Vikash Singh
  • 13,213
  • 8
  • 40
  • 70