Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python The Challenge

Kelly Musgrove
Kelly Musgrove
16,453 Points

Reassigned list is still deleting items from the original list?

In our previous lessons, it was taught that removing items from a list that has been reassigned will not delete from the original list. Why is it that the 'players' list here is empty after I run the while loop, even though it's the reassigned 'roster' list that's being deleted from?

players = []

add_new_player = input("Would you like to add a player to the list? (Yes/No)  ")
while add_new_player.upper() == "YES":
    new_player = input("Enter the name of the player to add to the team:  ")
    players.append(new_player)
    add_new_player = input("\nWould you like to add a player to the list? (Yes/No)  ")

if add_new_player.upper() == "NO":
    print("There are {} players on the team.".format(len(players)))
    print(players)

player_number = 1
roster = players

while len(roster) > 0:
    print("Player {}: {}".format(player_number, roster[0]))
    del roster[0]
    player_number += 1

print(players)

5 Answers

Hi Kelly

Have you heard of Python id-s and the id() function? If not, here's a short explanation for you:

  • the id() function returns a unique id for the specified object.
  • all objects in Python has its own unique id.
  • the id is assigned to the object when it is created.
  • the id is the object's memory address

So basically by roster = players you are not actually copying the list rather than just reassigning it which means that the id stays the same for both of the objects roster and players.

I've added 3 lines of code into your code after where you make the reassignment to demonstrate this, please check the OUTPUT section as well, the list is empty indeed in the end:

players = []

add_new_player = input("Would you like to add a player to the list? (Yes/No)  ")
while add_new_player.upper() == "YES":
    new_player = input("Enter the name of the player to add to the team:  ")
    players.append(new_player)
    add_new_player = input("\nWould you like to add a player to the list? (Yes/No)  ")

if add_new_player.upper() == "NO":
    print("There are {} players on the team.".format(len(players)))
    print(players)

player_number = 1
roster = players

print(f'\nThe id of players is {id(players)}')
print(f'The id of roster is {id(roster)}')
print('Both players and roster have the same id\n')

while len(roster) > 0:
    print("Player {}: {}".format(player_number, roster[0]))
    del roster[0]
    player_number += 1

print(players)

"""
OUTPUT:

Would you like to add a player to the list? (Yes/No)  yes
Enter the name of the player to add to the team:  Mike

Would you like to add a player to the list? (Yes/No)  yes
Enter the name of the player to add to the team:  Matt

Would you like to add a player to the list? (Yes/No)  no
There are 2 players on the team.
['Mike', 'Matt']

The id of players is 2191336012544
The id of roster is 2191336012544
Both players and roster have the same id

Player 1: Mike
Player 2: Matt
[]
"""

If you wish your original list players to be untouched you need to make a copy of it (EDIT: this means the lists will have their own unique id-s). There are many ways to do this. You can use slicing for instance like this roster = players[:]. This way your players list will not be affected.

I made the some changes to your code, used slicing and the original list stays unaffected. The list in the end is not empty:

players = []

add_new_player = input("Would you like to add a player to the list? (Yes/No)  ")
while add_new_player.upper() == "YES":
    new_player = input("Enter the name of the player to add to the team:  ")
    players.append(new_player)
    add_new_player = input("\nWould you like to add a player to the list? (Yes/No)  ")

if add_new_player.upper() == "NO":
    print("There are {} players on the team.".format(len(players)))
    print(players)

player_number = 1
roster = players[:]

print(f'\nThe id of players is {id(players)}')
print(f'The id of roster is {id(roster)}')
print('Players and roster have a different id\n')

while len(roster) > 0:
    print("Player {}: {}".format(player_number, roster[0]))
    del roster[0]
    player_number += 1

print(players)

"""
OUTPUT:

Would you like to add a player to the list? (Yes/No)  yes
Enter the name of the player to add to the team:  Mike

Would you like to add a player to the list? (Yes/No)  yes
Enter the name of the player to add to the team:  Matt

Would you like to add a player to the list? (Yes/No)  no
There are 2 players on the team.
['Mike', 'Matt']

The id of players is 2435709532928
The id of roster is 2435741032960
Players and roster have a different id

Player 1: Mike
Player 2: Matt
['Mike', 'Matt']
"""

Does this help? I tried to be as clear as possible by explaining this :-)

Kelly Musgrove
Kelly Musgrove
16,453 Points

Thanks so much! I had not learned about id's in Python... until now! I really appreciate the thorough explanation!

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,720 Points

What Ave said above is correct. And you can check the id() of the lists to see if these point to the same memory structure.

The short answer is-- lists in Python are mutable. When you assign roster = players both point to the same memory location. You need to make a copy of the list instead.

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.

Below is an implicit (shallow) copy using list slice method. Which works in Python 2.x and 3.x

roster = players[:]

Another more explict copy method is a "cast" instantiation. You explicitly tell Python you want a NEW list object

roster = list(players)

Below is a PEP20 compliant copy. It is more explicit but does the same thing as the slice method. This works only in Python 3.x

roster = players.copy()
Kelly Musgrove
Kelly Musgrove
16,453 Points

Thank you! This is very helpful as well.

Hi Jeff

Thank you for commenting on my post and making things even clearer. The last part of your comment where you show how to make explicit copies of a list was really helpful to me personally. As the Zen of Python states 'Explicit is better than implicit'. Thanks again!

Happy to help, Kelly!

This post has helped me a lot thanks to both Jeff and Ave. Also Kelly for bringing this problem up. I didn't have the same problem but my question was still answered along the way. Very helpful.