16

My python script:

N = 2  # 2*2 matrix

a = N * [0]
b = a

print(b)  # prints [0, 0]

for i in range(N):
    a[i] = N * [0]

for i in range(N):
    for j in range(N):
        a[i][j] = 0

print(a)  # prints [[0, 0], [0, 0]]

print(b)  # prints [[0, 0], [0, 0]]

Why does my second print(b) change? How to make it immutable? I'd like my b to still contain [0, 0].

4 Answers 4

28

Your understanding of "objects" in Python and variable assignments is flawed.

In a language like C, when you define a variable (say int a), a tiny area of memory is allocated and reserved for this variable and a is now something that refers to this area of memory. You can poke into this area, change it and find that a "has a" different value now. A statement like a = 2 (or a = b where b is another variable) takes the value of the right hand side and writes it into the memory location reserved for a. Now you can modify b as you wish but a will still retain the original value. This is why you can do things like a++ in C which means, "get the value of what a refers to, add one to it and write it back to the same location".

In Python, when you say x = [], a new list object is created and x is made to "point" to that list. Now any change you make to x is affecting this object. Suppose you say y = x, you will get another reference to the same object. Changing y (or x for that matter) will change the object which is now pointed to by x and y. This is what you've done with the B = A assignment. All things done to this object via A will be visible when you access it via B since they both point to the same object. In this sense, all variables in Python are like pointers in C. You can also understand why we don't have a ++ operator in Python since it's meaningless to modify the contents of a memory location like in C.

The solution suggested by others so far is suggesting that you make a new object with the exact same contents as the list pointed to by A and make B point to this copy. This way, if you modify A (or what A points to), B (or what B points to) will remain unchanged.

This however doesn't make B "immutable" (i.e. an object which cannot be modified in place). However, I think you have simply used the word erroneously and meant that you didn't want the aliasing to take place.

Sign up to request clarification or add additional context in comments.

4 Comments

So there is no way to make a variable immutable in python?
If you're asking for constants (which I take to mean a binding of a value to a symbol that can't be altered) during the lifetime of the program, then no, there isn't. There are workarounds but those are just that.
I guess the "++" remark is no more relevant? It is now a valid Python operator.
@Dr_Zaszuś I missed that. Do you have reference? Would love to know more.
20

When assigning objects in python, you assign references (something like pointers in C).

There are several ways to circumvent this but the IMHO most idiomatic is using copy:

import copy
B = copy.copy(A)

In some cases you even may want to used deepcopy(), have a look at the documentation for details.

Comments

7

The problem is:

B=A

now both point to the same object.

Try:

B = [i for i in A]

now B is a new list containing all the elements from A. Or simply:

B = A[:]

2 Comments

you can use B = A.copy() too
What you're referring to is called shallow copy and for lists it's simply B = list(A)
0

Change the way you assign B:

B = A

to

B = A[:]

1 Comment

This solution is good for arrays and only for them. It hides the problem rather than solves.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.