Why does my loop return an empty list error when I pass it a copied list, but does not error with an original list?

Question:

short_texts = ['I like the apple', 'I like the orange as well', 'Finally, I like the inside of a kiwi the best']
sent_messages = []


def send_messages(messages):
    
    while messages:
        popped_st = short_texts.pop(0)
        print(popped_st)
        sent_messages.append(popped_st)


send_messages(short_texts[:])

print(short_texts)
print(sent_messages)

Error>

I like the apple
    I like the orange as well
    Finally, I like the inside of a kiwi the best
    Traceback (most recent call last):
      File "C:UsersSteveDocumentspython_work8.11.py", line 13, in <module>
        send_messages(short_texts[:])
      File "C:UsersSteveDocumentspython_work8.11.py", line 8, in send_messages
        popped_st = short_texts.pop(0)
    IndexError: pop from empty list
    [Finished in 200ms]

If I get rid of the slice argument of the function call, the program works. Adding the slice, causes the "pop from empty list".

I am reading Python Crash Course, 2E, and in exercise 8.10.py, it requires me to pass a copy of the initial list to the function and print both the appended list, and the original list.

Obviously I have failed to grasp a concept here?

Asked By: Steven Torman

||

Answers:

You’re not modifying messages in the loop, so the while messages: condition never changes, and you have an infinite loop. You should be popping from messages, not short_texts. Then messages will eventually become empty, and the while messages: condition will be false and the loop stops.

def send_messages(messages):
    while messages:
        popped_st = messages.pop(0)
        print(popped_st)
        sent_messages.append(popped_st)

It works when you don’t use a slice to call the function, because then messages and short_texts refer to the same list. In that case, short_texts.pop(0) is equivalent to messages.pop(0). The slice makes a copy of the list.

Answered By: Barmar