Python Forum
how can a variable change if I haven't changed it? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: how can a variable change if I haven't changed it? (/thread-33227.html)



how can a variable change if I haven't changed it? - niminim - Apr-07-2021

I'm totally new to python.
I'm writing a simple code that is supposed to find random bingo statistics. The code works just fine until I'm trying to run it more than once in a for loop. Forget about the code, just check out the oldmatrix variable. I never set a new value to it and yet it changes on the second iteration. How can it be??

# Online Python compiler (interpreter) to run Python online.
# Write Python 3 code in this online editor and run it.
import random
print("Hello world")
bingo = 0
checkbingo = 0
basematrix = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
matrix = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
baselist = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]

for iter in range(2):
print("ïter =", iter)
print("basematrix = ", basematrix)
print("matrix = ",matrix)
#random punch
for punchnum in range(25):
n = random.randint(0, len(list)-1)
i = list[n]
matrix[round((i-i%5)/5)][round(i%5)] = 1
list.pop(n)
#check bingo
for x in range(5):
for y in range(5):
checkbingo = checkbingo + (matrix[x][y])
if checkbingo == 5:
bingo = 1
checkbingo = 0

if bingo == 0:
for y in range(5):
for x in range(5):
checkbingo = checkbingo + (matrix[x][y])
if checkbingo == 5:
bingo = 1
checkbingo = 0
print(punchnum," = ", bingo)

print("basematrix = ", basematrix)
matrix = basematrix
print("matrix = ",matrix)
list = baselist


RE: how can a variable change if I haven't changed it? - bowlofred - Apr-07-2021

First, list and iter are names of classes in python. You shouldn't use them as variable names or you hide the ability to use the class namespaces.

You don't have anything named oldmatrix in your code, but I can guess what you've done is assumed that assigning a list copies the data rather than just a reference to it. (Please put your code in "python" tags so that the indentation is preserved).

I've made some other code to show how this can affect you and one way to avoid it.

baselist = [0, 0, 0, 0]
working_list = baselist # copies the object, not the elements inside

working_list[2] = "XX"
print(f"{working_list=}")
print(f"{baselist=}")
print()

# Note "baselist" has changed without explicitly doing so because it is the same object
# as working_list.

baselist = [0, 0, 0, 0]
working_list = baselist.copy()  # This is a copy and the two objects are different

working_list[2] = "XX"  # doesn't change baselist now.
print(f"{working_list=}")
print(f"{baselist=}")
Output:
working_list=[0, 0, 'XX', 0] baselist=[0, 0, 'XX', 0] working_list=[0, 0, 'XX', 0] baselist=[0, 0, 0, 0]



RE: how can a variable change if I haven't changed it? - jefsummers - Apr-07-2021

Great youtube from PyCon that explains this behavior, mutable and immutable values, etc.

Pycon 2015 Ned Batchelder


RE: how can a variable change if I haven't changed it? - niminim - Apr-07-2021

(Apr-07-2021, 05:14 PM)bowlofred Wrote: First, list and iter are names of classes in python. You shouldn't use them as variable names or you hide the ability to use the class namespaces.

You don't have anything named oldmatrix in your code, but I can guess what you've done is assumed that assigning a list copies the data rather than just a reference to it. (Please put your code in "python" tags so that the indentation is preserved).

I've made some other code to show how this can affect you and one way to avoid it.

baselist = [0, 0, 0, 0]
working_list = baselist # copies the object, not the elements inside

working_list[2] = "XX"
print(f"{working_list=}")
print(f"{baselist=}")
print()

# Note "baselist" has changed without explicitly doing so because it is the same object
# as working_list.

baselist = [0, 0, 0, 0]
working_list = baselist.copy()  # This is a copy and the two objects are different

working_list[2] = "XX"  # doesn't change baselist now.
print(f"{working_list=}")
print(f"{baselist=}")
Output:
working_list=[0, 0, 'XX', 0] baselist=[0, 0, 'XX', 0] working_list=[0, 0, 'XX', 0] baselist=[0, 0, 0, 0]

First, thank you, you are super helpful.
I indeed meant basematrix.
I made some changes according to your advice. Still doesn't;t work, basematrix get changed. I'm sure I'm doing a foolish mistake but I can't find it,

# Online Python compiler (interpreter) to run Python online.
# Write Python 3 code in this online editor and run it.
import random
print("Hello world")
bingo = 0
checkbingo = 0
basematrix = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
matrix = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
baselist = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
punchlist = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]

for runningtimes in range(2):
    print("runningtimes =", runningtimes)
    print("basematrix = ", basematrix)
    print("matrix = ",matrix)
    #random punch
    for punchnum in range(25):
        n = random.randint(0, len(punchlist)-1)
        i = punchlist[n]
        matrix[round((i-i%5)/5)][round(i%5)] = 1
        punchlist.pop(n)
        #check bingo
        for x in range(5):
            for y in range(5):
                checkbingo = checkbingo + (matrix[x][y])
                if checkbingo == 5:
                    bingo = 1
            checkbingo = 0
        
        if bingo == 0:
            for y in range(5):
                for x in range(5):
                    checkbingo = checkbingo + (matrix[x][y])
                    if checkbingo == 5:
                        bingo = 1
                checkbingo = 0
        print(punchnum," = ", bingo)
   
    print("basematrix = ", basematrix)
    matrix = basematrix.copy()
    print("matrix = ",matrix)
    punchlist = baselist.copy()
    print("punchlist =", punchlist)
   
    
  



RE: how can a variable change if I haven't changed it? - deanhystad - Apr-07-2021

You need to do a deep copy
import copy
a = [[1, 1], [2, 2]]

b = a.copy()
print('Copy')
for x, y in zip(a, b):
    print(x, y, id(x), id(y))


print('\nDeep Copy')
b = copy.deepcopy(a)
for x, y in zip(a, b):
    print(x, y, id(x), id(y))
Output:
Copy [1, 1] [1, 1] 2858215123584 2858215123584 [2, 2] [2, 2] 2858215123072 2858215123072 Deep Copy [1, 1] [1, 1] 2858215123584 2858215122240 [2, 2] [2, 2] 2858215123072 2858215123520
When you copy a list of lists the copy is a new list that contains lists from the original. To create copies of the contents you should use deepcopy from the copy library. Notice that the object ID's match when doing b = a.copy(), but when doing b = copy.deepcopy(a), new lists are created for the copy.


RE: how can a variable change if I haven't changed it? - niminim - Apr-07-2021

(Apr-07-2021, 06:33 PM)deanhystad Wrote: You need to do a deep copy
import copy
a = [[1, 1], [2, 2]]

b = a.copy()
print('Copy')
for x, y in zip(a, b):
    print(x, y, id(x), id(y))


print('\nDeep Copy')
b = copy.deepcopy(a)
for x, y in zip(a, b):
    print(x, y, id(x), id(y))
Output:
Copy [1, 1] [1, 1] 2858215123584 2858215123584 [2, 2] [2, 2] 2858215123072 2858215123072 Deep Copy [1, 1] [1, 1] 2858215123584 2858215122240 [2, 2] [2, 2] 2858215123072 2858215123520
When you copy a list of lists the copy is a new list that contains lists from the original. To create copies of the contents you should use deepcopy from the copy library. Notice that the object ID's match when doing b = a.copy(), but when doing b = copy.deepcopy(a), new lists are created for the copy.

Thanks pal, you've solved my problem and taught me a lesson.