Observe the following code:
class permcom:
def __init__(self, INPUT_SET, IS_PERM, REPETITION):
self.end_set = []
self.input_set = INPUT_SET
self.is_perm = IS_PERM
self.repetition = REPETITION
def helpfunc(self, seen, depth, current):
if depth == 0:
self.end_set.append(seen)
else:
for i in range(0, len(self.input_set)):
if(self.repetition):
seen.append(self.input_set[i])
if(self.is_perm):
self.helpfunc(seen, depth - 1, 0)
else:
self.helpfunc(seen, depth - 1, i)
del seen[-1]
# return all permutations with repetition
def rapwr(INPUT_SET, subset_size):
instance = permcom(INPUT_SET, True, True)
A = []
instance.helpfunc(A, subset_size, 0)
return instance.end_set
A = [1,2,3]
B = rapwr(A, 2)
for i in range(0, len(B)):
print B[i]
The output is the following:
[]
[]
[]
[]
[]
[]
[]
[]
[]
However, the intended output is this:
[1, 1]
[1, 2]
[1, 3]
[2, 1]
[2, 2]
[2, 3]
[3, 1]
[3, 2]
[3, 3]
I've spent way too much time looking at this code and, unfortunately, I still cannot figure out exactly what's wrong. There must be something fundamental that I'm not understanding about how member variables work in Python, but I still don't quite understand what's going on here and why the code isn't working. Can somebody explain this?
Short answer
What you need is list slicing [:]
. Changing the statement
if depth == 0:
self.end_set.append(seen)
to
if depth == 0:
self.end_set.append(seen[:])
Gives the expected answer
Long answer
Try this sample code in a python interpreter
a = [1,2]
b = []
b.append(a)
a[0] = 3
print b
# output is [[3, 2]]
Now try this code
a = [1,2]
b = []
b.append(a[:])
a[0] = 3
print b
# output is [[1, 2]]
Why did this happen? In the first case when you appended a
to the list b
, it was not the value of a
that was appended, it was a reference/tag to the [1,2]
value. You can verify this by printing id(b[0])
and id(a)
. Both will be the same value . Hence when you modify any value in the a
list, the value in the b
list also changes.
Same is the case in your code. Since you are doing del seen[-1]
, the corresponding value in self.end_set
is also removed. You can confirm this by printing the value of self.end_set
in the depth == 0
block.
To avoid this you append a clone of one list to the other list. This is done by using the splicing syntax [:]
. This creates a copy of the list from the start to the end of the list. You can learn more about slicing here .
PS: Try printing the id()
of the two lists when you use slicing, the values will be different
Here is what I got
a = [1,2]
b = []
b.append(a)
print id(b[0])
#output is 43337352L
print id(a)
#output is 43337352L
b = []
b.append(a[:])
print id(b[0])
#output is 43337608L
Take a look at this python memory model diagram for a better understanding of the above
Update: some advice
B
and self.input_set
are both lists, prefer using the idiomatic for i in B
and for i in self.input_set
. rapwr
can be renamed to return_all_permutations_with repetition
. Though the name is large, its easy to understand what it does without looking at the method body now.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.