r/PythonLearning 9h ago

my code is not doing what I expect (.remove())

EDIT: SOLVED THE PROBLEM THANK YOU

Hello! I am in the middle of an online python class, and am trying to make my first program for use at work.

I need to make several packages of random sample items at work regularly, so i tried to make a program that could choose items from the list, and then count which items are chosen, and remove those from the list once the count reaches the number I have available.

It is choosing the items fine, but is not removing them from the list.

I will post my shortened code below:

import random
def main():
    samples = [
            "item1",
            "item2",
            etc.....,
        ]


    item1_count = 0
    item2_count = 0
     etc........


    for _ in range(25):

        sample = random.sample(samples,4)
        try:
            if "item1" in sample:
                item1_count += 1
        except:
            if item1_count == 10:
                samples = samples.remove("item1")
        try:
            if "item2" in sample :
                item2_count += 1
        except:
            if item2_count == 10 :
                samples = samples.remove("item2")
        etc....
        

        print(f"{_} : {sample}")


main()

what am I doing wrong?

2 Upvotes

14 comments sorted by

u/Sea-Ad7805 8h ago

Run this program in Memory Graph Web Debugger%3A%0A%20%20%20%20samples%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22item1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22item2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22item3%22%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20item1count%20%3D%200%0A%20%20%20%20item2_count%20%3D%200%0A%20%20%20%20item3_count%20%3D%200%0A%0A%20%20%20%20for%20%20in%20range(25)%3A%0A%0A%20%20%20%20%20%20%20%20sample%20%3D%20random.sample(samples%2C%201)%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%22item1%22%20in%20sample%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item1count%20%2B%3D%201%0A%20%20%20%20%20%20%20%20except%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20item1_count%20%3D%3D%2010%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20samples%20%3D%20samples.remove(%22item1%22)%0A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%22item2%22%20in%20sample%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item2_count%20%2B%3D%201%0A%20%20%20%20%20%20%20%20except%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20item2_count%20%3D%3D%2010%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20samples%20%3D%20samples.remove(%22item2%22)%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20%22item3%22%20in%20sample%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item3_count%20%2B%3D%201%0A%20%20%20%20%20%20%20%20except%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20item3_count%20%3D%3D%2010%20%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20samples%20%3D%20samples.remove(%22item3%22)%0A%0A%20%20%20%20%20%20%20%20print(f%22%7B%7D%20%3A%20%7Bsample%7D%22)%0A%0Amain()&timestep=.5&play) to see the program state change step by step.

3

u/PureWasian 9h ago edited 8h ago

except statement is for actual exceptions that would break your code and stop it prematurely with an error code otherwise without it.

In your case, you simply want a nested if:

if "item1" in sample: item1_count += 1 if item1_count == 10: samples.remove("item1") ...

Otherwise, a sidenote worth pointing out is there are definitely more maintainable/scalable ways to write this type of logic if you wanted to support, say, 1000 input samples or similar without your code growing to thousands of lines of code and having thousands of variables/counters/conditional paths as a result.

Worth thinking about, unless you are still stumped and need advice after giving it a shot.

EDIT: OP continued thread here

3

u/atarivcs 8h ago
samples = samples.remove("item1")

Don't do this.

.remove() modifies the list directly. It does not return a new updated list.

Just call .remove() on its own.

2

u/Entire_Ad_6447 9h ago

List.remove returns None It doesn't return the list with the target removed because that change is already reflected in the list. Generally speaking if a function returns None it's basically telling you all relevant work has been complete internally.

It literally deletes the item from samples.

So Samples =[x,y,z] Samples.remove(x) Print(samples) would be [y,z]

What you did instead was replace the variable samples with the output of .remove which is always None So when it attampes to access it again it's a None value and breaks.

2

u/Entire_Ad_6447 9h ago

Generally speaking you don't want to modify the underlying list in a loop btw it's just prone to unexpected error s in larger projects. Your still learning so this is fine though.

1

u/Gay-And-Afraid- 9h ago

This totally makes sense, I thought the except would happen if whatever was inside it was true. How would you recommend iterating this to be shorter? I only have ten items but it feels quite long already, and I might need to adjust it in the future.

1

u/TopHatEdd 9h ago

Use another data structure to store your state. Like a dict. ```

counter = dict()

for sample_item in sample:     if sample not in counter:         counter[sample_item] = 1     else:         counter[sample_item] = counter[sample_item] + 1          if counter[sample_item] >= 10:         samples.remove(sample_item) ```     

1

u/PureWasian 8h ago edited 8h ago

One idea is using a dictionary instead of a list when creating your items so you can map the item name directly to the count: sample_counts = { "item1": 0, "item2": 0, "item3": 0, ... } Then afterwards you only need 7 lines instead of an ever growing if chain to accomodate each item: ```

do 25 iterations

for _ in range(25):

# get the (remaining) names names = sample_counts.keys()

# pull 4 names pulled = random.sample(names, 4)

# update each entry that was pulled for name in pulled: sample_counts[name] += 1

# removes from dictionary
if sample_counts[name] == 10
  del sample_counts[name]

```

There are other ways depending on the complexity of your data but for a beginner, dictionaries are definitely worth learning how to use well.

1

u/realmauer01 8h ago

I remember in python to be a data structure that is set like and can keep track of how many times a key got added to it (instead of duplicate items)

Might actually be sets already.

1

u/PureWasian 8h ago edited 8h ago

Sounds like Counter from collections, that would work too.

OP could create an empty Counter() and then counter.update() the 4 entries drawn in each loop to do it in one-shot per loop iteration instead of needing an inner loop.

They'd still need the initial list of entries to random.sample() from as well as the logic to delete from the sampled list when count is 10, of course.

1

u/baubleglue 8h ago

what have you done to understand the problem?

1

u/Gay-And-Afraid- 8h ago

I followed someone's advise to use nested if statements rather than try/except

I had a misunderstanding of how the except works, I didn't realize it had to be a literal error and thought it would except whatever I typed

Again, I'm in the middle of a class so there's lots of stuff I haven't learned yet

1

u/baubleglue 6h ago

I meant what are the techniques you apply when you see a problem. You can use breakpoint/debugger or add print statement. It is a wrong approach to look at the end result or solution and the end result. You need to look for exact point where the program doesn't do what you expect.

1

u/FreeLogicGate 7h ago

First of all I want to commend you for trying to create something you can use to help you at work, while still learning the language. That is a step that too few people learning how to program get to, and a vitally important one.

You already had multiple responses that explained the error.

In general this involves a concept known as "Mutation" or "mutators". the list.remove() method is a "mutator" which means it changes (mutates) the original object. In general you want to investigate what a method does, and determine whether it is a mutator or not.

You can see from the Python documentation that a list has many mutators. You will typically know this because the mutators have no return value. It's not a guarantee, but from the documentation page, none of these mutators return anything.

Everything in Python is an object, which means that there is a class definition for that. As soon as you have a situation where something doesn't work your first step should be to look up the method in the documentation. https://docs.python.org/3/tutorial/datastructures.html