You cannot pass anything by value in Python. If you want to make a copy of a, you can do so explicitly, as described in the official Python FAQ:
b = a[:]
Answer from phihag on Stack OverflowYou cannot pass anything by value in Python. If you want to make a copy of a, you can do so explicitly, as described in the official Python FAQ:
b = a[:]
To copy a list you can use list(a) or a[:]. In both cases a new object is created.
These two methods, however, have limitations with collections of mutable objects as inner objects keep their references intact:
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = list(a)
>>> c[0].append(9)
>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>>
If you want a full copy of your objects you need copy.deepcopy
>>> from copy import deepcopy
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = deepcopy(a)
>>> c[0].append(9)
>>> a
[[1, 2], [3], [4]]
>>> b
[[1, 2], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>>
Aren't lists pass by reference in Python?
python - Is list pass by value or by reference? - Stack Overflow
python - Copy a list of list by value and not reference - Stack Overflow
Getting a list of arrays into a dataframe
You can use [:], but for list containing lists(or other mutable objects) you should go for copy.deepcopy():
lis[:] is equivalent to list(lis) or copy.copy(lis), and returns a shallow copy of the list.
In [33]: def func(lis):
print id(lis)
....:
In [34]: lis = [1,2,3]
In [35]: id(lis)
Out[35]: 158354604
In [36]: func(lis[:])
158065836
When to use deepcopy():
In [41]: lis = [range(3), list('abc')]
In [42]: id(lis)
Out[42]: 158066124
In [44]: lis1=lis[:]
In [45]: id(lis1)
Out[45]: 158499244 # different than lis, but the inner lists are still same
In [46]: [id(x) for x in lis1] = =[id(y) for y in lis]
Out[46]: True
In [47]: lis2 = copy.deepcopy(lis)
In [48]: [id(x) for x in lis2] == [id(y) for y in lis]
Out[48]: False
This might be an interesting use case for a decorator function. Something like this:
def pass_by_value(f):
def _f(*args, **kwargs):
args_copied = copy.deepcopy(args)
kwargs_copied = copy.deepcopy(kwargs)
return f(*args_copied, **kwargs_copied)
return _f
pass_by_value takes a function f as input and creates a new function _f that deep-copies all its parameters and then passes them to the original function f.
Usage:
@pass_by_value
def add_at_rank(ad, rank):
ad.append(4)
rank[3] = "bar"
print "inside function", ad, rank
a, r = [1,2,3], {1: "foo"}
add_at_rank(a, r)
print "outside function", a, r
Output:
"inside function [1, 2, 3, 4] {1: 'foo', 3: 'bar'}"
"outside function [1, 2, 3] {1: 'foo'}"
my_list = [-3, 3]
def change_list(my_list):
my_list = 1
change_list(my_list)
print(my_list)This outputs: [-3, 3]
Why doesn't the global my_list change?
Because python passes lists by reference
This means that when you write "b=a" you're saying that a and b are the same object, and that when you change b you change also a, and viceversa
A way to copy a list by value:
new_list = old_list[:]
If the list contains objects and you want to copy them as well, use generic copy.deepcopy():
import copy
new_list = copy.deepcopy(old_list)
Since Python passes list by reference, A and B are the same objects. When you modify B you are also modifying A. This behavior can be demonstrated in a simple example:
>>> A = [1, 2, 3]
>>> def change(l):
... b = l
... b.append(4)
...
>>> A
[1, 2, 3]
>>> change(A)
>>> A
[1, 2, 3, 4]
>>>
If you need a copy of A use slice notation:
B = A[:]