views:

173

answers:

3

This may be for most languages in general, but I'm not sure. I'm a beginner at Python and have always worked on copies of lists in C# and VB. But in Python whenever I pass a list as an argument and enumerate through using a "for i in range," and then change the value of the list argument, the input values actually changes the original list. I thought Python was supposed to pass arguments by value by default so that once the function is finished I still have the original values from before I called the function. What am I missing? Thanks!

+5  A: 

Python does pass arguments by value but the value you are receiving is a copy of the reference (incidentally this is the exact same way that C#, VB.NET, and Java behave as well).

This is the important thing to remember:

Objects are not passed by reference - object references are passed by value.

Since you have a copy of the reference, any operation on what that reference points to will be just as if you were holding the original reference itself.

Andrew Hare
People often wonder what the difference between passing by reference and passing references by value is. The difference is that when you pass x by reference, "x = new_value" will change the value of a callee's variable (where x is a parameter name). That doesn't happen in Python (or the other languages Andrew mentioned) which is why we do not say that they pass by reference.
Laurence Gonsalves
Ah, I see. So does this have anything to do with pointers, by chance?
Austin
Yes, it works just like passing a pointer by value.
lacker
A: 

To add to Andrew's answer, you need to explicitly make a copy of a list if you want to retain the original. You can do this using the copy module, or just do something like

a = [1,2]
b = list(a)

Since copying objects usually implies a performance hit, I find it helpful to explicitly use the copy module in my larger projects. That way, I can easily find all the places where I'm going to use a bunch more memory.

Igor
also b=a[:] #blah
gnibbler
+3  A: 

Python -- just like Java does for anything but primitive scalars, and like C# and VB.NET do for the default kind parameters as opposed to boxed types and out / ref parms -- passes "by object reference" (search for that phrase here -- it's how Guido, Python's architect and creator, uses to explain this argument-passing concept).

Every name is a reference to some object; passing a name (or any other expression) as an argument is just creating yet another reference to the same object (which the function body can access through the parameter's name). ((There's no such thing as "a reference to a name": there are names, which are one kind of reference to objects, and object -- period)).

When you're passing a mutable object, i.e. one which has mutating methods (like for example a list), the called function can mutate the object by calling, directly or indirectly, its mutating methods. ((By "indirectly", I mean "through operators" -- for example:

somelist[len(somelist):] = [whatever]

is exactly identical to somelist.append(whatever).))

When you want to pass a list into a function, but do not want the function to be able to mutate that list in any way, you must pass a copy of the list instead of the original -- just like in Java, C#, VB.NET.

Be very clear about the distinction between rebinding a name and mutating an object. Rebinding the name ("barename", that is -- qualified-names are different;-) only affects that name -- NOT any object whatsoever. For example:

def f1(alist):
  alist = [23]

def f2(alist):
  alist[:] = [23]

Can you spot the difference between these two functions? One is rebinding the barename alist -- without any effect whatsoever on anything. The other is mutating (altering, changing, ...) the list object it received as its argument -- by setting its content to be a one-item list with an int as its sole item. Completely, utterly different things!!!

Alex Martelli
In C#, structs are not passed by reference. A copy is created every time one is assigned.
recursive
@recursive, sure, but lists aren't structs.
Alex Martelli
I know that, but I was just trying to say that I thought your first sentence was too general. As it applies to the original question though, it's correct.
recursive
Alex Martelli