0

I am attempting the Probability Calculator from freecodecamp, which can be found Here

In a class function to randomly select n items from a list, I access the contents of my list via self.contents, which is an instance variable for whatever hat filled with balls I make. My function looks as such:

def draw(self,num_balls_drawn):
  randomlist = []
  templist = self.contents
  if num_balls_drawn <= len(templist):
    for x in range(num_balls_drawn):
      popped = templist.pop(random.randint(0, len(templist)-1)) # random has been imported
      randomlist.append(popped)
    return randomlist 

  else:
    return self.contents #If you ask for more items than there are in list, just returns list

Therefore, when I create a class instance using this code:

class Hat:
  def __init__(self,**kwargs):
    self.__dict__.update(kwargs)
    contents=[]
    for key in self.__dict__:
      for x in range(self.__dict__.get(key)):
        contents.append(key)
    self.contents= contents

And then create an instance with hat = Hat(blue=4, red=2, green=6), then testing my functions withprint(hat.contents) print(hat.draw(7)) print(hat.contents) print(hat.draw(7))

I would hope to be given a list of ['blue', 'blue', 'blue', 'blue', 'red', 'red', 'green', 'green', 'green', 'green', 'green', 'green'] for hat.contents and a list such as ['blue', 'blue', 'red', 'green', 'blue', 'blue', 'green'] for hat.draw(7)

However, on the second attempt of using these statements, I instead am returned ['blue', 'blue', 'green', 'green', 'green'] and ['blue', 'blue', 'green', 'green', 'green']

Both of which are somehow a length of only 5.

It seems despite setting up a temporary list templist, my self.contents is still shortened everytime I pop an item out of templist.

If anyone could offer a solution to my Issue that would be appreciated.

1
  • 1
    Can you please create a minimal reproducible example? Provide the result you expect and something that we can run and get the wrong result. Commented Dec 17, 2020 at 21:13

1 Answer 1

1

The problem with your code is that self.contents is passed by address and not by value. What you could do is change templist = self.contents to templist = self.contents[:]. The new draw function would be as follows:

def draw(self,num_balls_drawn):
  randomlist = []
  templist = self.contents[:]
  if num_balls_drawn <= len(templist):
    for x in range(num_balls_drawn):
      popped = templist.pop(random.randint(0, len(templist)-1)) # random has been imported
      randomlist.append(popped)
    return randomlist 

  else:
    return self.contents #If you ask for more items than there are in list, just returns list
Sign up to request clarification or add additional context in comments.

2 Comments

what should I research to learn more about why what you changed works? Thanks
@FredB look for passing by value and by reference, I believe it's easier to learn it in C or C++ than in Python, here's a small explanation that can help you understand it better Pass by reference vs value in Python. What you should know, is that you should be careful assigning list, always try to copy/deepcopy the list depending on how you want your code to behave. To understand those concepts please refer to the following link: Shallow vs Deep Copying of Python Objects

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.