0

So basically i've observed that in python3 if i do something like

a = 5
def addFive(x):
    x+=5
    return x
print(addFive(a),a)

The output will be "10 5" since a is not changed by the function. However the same does not happen for lists:

a = [1,2,3]

def b(x):
    z = x
    z.append(10)

b(a)
print(a)

When i run the function it changes the actual list.

Now to my Question: Why does this happen, where can i read up more about this(Honestly have no idea how to word my google search) and how can i avoid this. Please feel free to redirect me to other articles as this could be a common problem but I honestly couldn't find anything similar.

Thanks in advance :)

HristoM
  • 23
  • 2
  • 6
  • 1
    Read the paragraph on mutable vs. immutable values for your Python version: [Python 2 Data Model](https://docs.python.org/2/reference/datamodel.html#objects-values-and-types) or [Python 3 Data Model](https://docs.python.org/3/reference/datamodel.html#objects-values-and-types). – Shashank Apr 14 '15 at 20:47
  • 2
    @Shashank you should link to the [Python 3](https://docs.python.org/3/reference/datamodel.html#objects-values-and-types) doc on same. – aruisdante Apr 14 '15 at 20:48
  • Also [this FAQ](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference). – TigerhawkT3 Apr 14 '15 at 20:53

2 Answers2

1

Use the copy module.

import copy

a = [1,2,3]

def b(x):
    z = copy.deepcopy(x)
    z.append(10)
    return z

b(a)
print(a)

This prints

[1, 2, 3, 10]
[1, 2, 3]
abcd
  • 10,215
  • 15
  • 51
  • 85
  • 1
    `z = x[:]` will do it – itzMEonTV Apr 14 '15 at 20:51
  • This is not an answer to the question. Also why was this upvoted? It recommends the use of copy.deepcopy when that it might not even be what the OP was looking for. We only need a shallow copy in this case and that can be done with x[:] or list(x). – Shashank Apr 14 '15 at 20:52
  • it answers "how can i avoid this," but yeah, doesn't answer the other questions. it's a partial answer. i'll expand it. – abcd Apr 14 '15 at 20:54
  • true, only a shallow copy is needed if the contents of the list are ints. but if a solution is desired when the contents of the list can be anything, `deepcopy` is the way to go. – abcd Apr 14 '15 at 21:01
0

Each element in a Python list is a location in memory, so when you modify an element, you're actually modifying that reference in memory. So if you're familiar with C++, passing a list into a function in Python, is similar in concept to passing by reference.

notorious.no
  • 4,919
  • 3
  • 20
  • 34
  • Bad explanation of what's going on, since in C++ I could do `int& x` and that's impossible to do in Python. It's actually because `list` is mutable. Everything in Python is pass by assignment, and the `=` operator is actually assigning pointers, not values. Read the linked duplicate. – aruisdante Apr 14 '15 at 20:50
  • i see your point. I was trying to suggest that how he's passing a list as an argument, is similar in concept to how one would pass params into a function by reference in C++. – notorious.no Apr 14 '15 at 20:56
  • But this has less to do with passing-references-by-value than it has to do with mutability vs immutability. `list.append` is a mutation of an object, `__add__` method returns a brand new object because ints are immutable. I like the direction you're taking with this answer but it can be improved. – Shashank Apr 14 '15 at 20:57
  • You learn something new everyday around here :) – notorious.no Apr 14 '15 at 21:01