Python: Fun problem. Solving Program is Bugged. Why?

  • Context: Python 
  • Thread starter Thread starter Swimmingly!
  • Start date Start date
  • Tags Tags
    Fun Program Python
Click For Summary

Discussion Overview

The discussion revolves around a Python programming problem related to a function that processes a list of lists representing mathematicians and their secret numbers. Participants are exploring the cause of a bug that leads to unintended changes in the data structure used in the program.

Discussion Character

  • Technical explanation
  • Debugging
  • Exploratory

Main Points Raised

  • One participant hypothesizes that the number of phone calls needed for all mathematicians to know each other's secret numbers can be determined through a brute force approach.
  • The participant describes a bug where the list D, which holds the mathematicians' known numbers, unexpectedly changes to a list of sets during function execution.
  • Another participant explains that the issue arises because assigning A = D creates a reference to D rather than a copy, leading to unintended modifications of D.
  • A suggestion is made to create a new list from D using A = list(D) to avoid the reference issue.
  • A later reply clarifies that using a shallow copy still retains references to mutable objects, which can lead to further changes in the original list.
  • Participants discuss the use of the copy module to create a deep copy of D to prevent changes in the original list.

Areas of Agreement / Disagreement

Participants generally agree on the nature of the problem related to mutable and immutable objects in Python, but there is no consensus on the best approach to resolve the issue, as different copying methods are suggested.

Contextual Notes

The discussion highlights the limitations of shallow copying in Python when dealing with lists of mutable objects, and the need for a deep copy to avoid unintended modifications.

Swimmingly!
Messages
43
Reaction score
0
I hope I'm in the right section.
This part is not important but this is thought behind the program.
If you have n-mathematicians and each has a secret number. How many phone calls have to be made for all mathematicians to know all numbers? In this brute force approach I, hypothesize that you need m calls and and try all combinations possible. When it works it'll print 1, if not it prints 0.
D represents what numbers each mathematician knows.
X represents the combination of phone calls chosen.

The bug is this:
D is a list of lists. X is a list.
The function at "def F(D,X):", makes A=D, makes some additions on A (eg: A+=A[j]), and then turns A into a list of sets. [set()...]
The loop at bottom repeats this process for all possible X. But somehow D is changed and turns into a list of sets, and since I can't add sets it stops! But why did D become a list of sets? I never tell D to change in the loop.

Code:
m=3
n=3

X=[]
Z=[]
D=[]
for i in range(0,2*m):
	X.append(0)
	Z.append(n-1)	
for i in range(0,n):
	D.append([i])
print 'X,Z,D=',X,Z,D

def F(D,X):
	A=D
	print 'D=',D							#Here for debugging purposes:
	print 'A=',A							#Here for debugging purposes:
	for i in range(0,m):
		A[X[2*i]]+=[X[2*i+1]]
		A[X[2*i+1]]=A[X[2*i]]
	for i in range(0,n):
		A[i]=set(A[i])
	return A

def T(A):
	s=0
	for i in range(0,n-1):
		if A[i]==A[i+1]:
			s+=1
	if s==n-1:
		return 1
	else:
		return 0

i=2*m-1
while X!=Z:
	if X[i]!=n-1:
		if i==2*m-1:
			print T(F(D,X))
		X[i]+=1
		i=2*m-1
	else:
		if i==2*m-1:
			print T(F(D,X))
		X[i]=0
		i-=1

Output:
Code:
X,Z,D= [0, 0, 0, 0, 0, 0] [2, 2, 2, 2, 2, 2] [[0], [1], [2]]
D= [[0], [1], [2]]
A= [[0], [1], [2]]
0
D= [set([0]), set([1]), set([2])]
A= [set([0]), set([1]), set([2])]
Traceback (most recent call last):
  File "blahblah.py", line 40, in <module>
    print T(F(D,Z))
  File "blahblah.py", line 19, in F
    A[Z[2*i]]+=[Z[2*i+1]]
TypeError: unsupported operand type(s) for +=: 'set' and 'list'
Press any key to continue . . .
 
Technology news on Phys.org
This is a common stumbling block. You need to be very clear about the difference between mutable and immutable objects in Python. The problem is, A = D leaves A not as a copy of D, but as a reference to the actual D object. They're now just two ways of referencing the same data.

You'll need to create a new list from the other. Here's a way to do it:

A = list(D)

I strongly suggest you find more materials on how mutable and immutable objects, and references, work in Python. That'll help prevent some serious pain later, trust me. :)
 
I tried what you said and changed it to:
Code:
def F(D,X):
	A=list(D)
	print 'D=',D
	for i in range(0,m):

but the output is:

Code:
X,Z,D= [0, 0, 0, 0, 0, 0] [2, 2, 2, 2, 2, 2] [[0], [1], [2]]
D= [[0], [1], [2]]
0
D= [[0, 0, 0, 0], [1], [2]]
0
D= [[0, 0, 0, 0, 0, 0, 1], [1], [2]]
0
D= [[0, 0, 0, 0, 0, 0, 1, 0, 0, 2], [1], [2]]
0

ie D is still changing. ie A is still a "reference to D".
I will however read about these "mutable and immutable objects and references". I learned python through copying and testing so sometimes I end up being ignorant about these things. Thanks a lot for giving me a lead on the problem.

Edit: BOTH the codes are INCOMPLETE. I don't need to post it all. I posted what matters.
 
Last edited:
Swimmingly! said:
ie D is still changing. ie A is still a "reference to D".
I will however read about these "mutable and immutable objects and references". I learned python through copying and testing so sometimes I end up being ignorant about these things. Thanks a lot for giving me a lead on the problem.

Ah, I haven't had time to go through your code in great detail, but remember that the method I gave you makes a "shallow copy" of the list, and any mutable objects in that list will still be the original references from the original list. That is, a list of lists, copied in this way, will be a new list containing the lists that were contained in the original one.

By the way, another method of making a shallow copy, for future reference, is A = D[:].

Anyways, try a deep copy using the copy module, which will make full copy of everything:

Code:
import copy

A = copy.deepcopy(D)

I'll check back in tomorrow in case you're still stuck. Good luck, and you're welcome! :)
 

Similar threads

  • · Replies 15 ·
Replies
15
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 28 ·
Replies
28
Views
5K
  • · Replies 1 ·
Replies
1
Views
5K
  • · Replies 8 ·
Replies
8
Views
2K
  • · Replies 18 ·
Replies
18
Views
2K
  • · Replies 9 ·
Replies
9
Views
3K