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!
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
Robert Baucus3,400 Points
Subclassing Built-Ins, why are we using copy.copy ?
At a certain point in the video Kenneth explains why he is using copy.copy in the following function: (from the transcript:)
Now why am I using copy.copy? Well, if they send in something mutable, like say, another list, each member in that filled list or each member in our filled list that was a copy of that list would be the same member if we weren't using copy.copy. If you changed one of them it would change all of the others too because we're just putting in references to that list.
#example he is talking about in the transcript: import copy class FilledList(list): def __init__(self, count, value, *args, **kwargs): super().__init__() for _ in range(count): self.append(copy.copy(value))
I can't follow what he is talking about. Could someone please shed some light on this?
Chris FreemanTreehouse Moderator 68,390 Points
Great question! In python, objects are referenced by their location in memory. This location can be seen using the
When appending an item to a list, it is the id of the item that is append, not the actual item.
# set an initial value >>> value = [1, 2, 3] >>> result =  >>> for _ in range(5): ... result.append(value) ... >>> for item in result: ... print(id(item)) ... 18867400 18867400 18867400 18867400 18867400 # All of the IDs are the same >>> print( result) [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]] # because the IDs are all the same, modifying one is the same # as modifying all since the all point to the same object id >>> result = 9 >>> print( result) [[1, 9, 3], [1, 9, 3], [1, 9, 3], [1, 9, 3], [1, 9, 3]] # Trying again using copy >>> import copy # reset result >>> result =  >>> for _ in range(5): ... result.append(copy.copy(value)) ... >>> print( result) [[1, 9, 3], [1, 9, 3], [1, 9, 3], [1, 9, 3], [1, 9, 3]] # This looks the same, but check out the IDs >>> for item in result: ... print(id(item)) ... 18908872 18909640 18909768 18909064 18909832 # All different!! # now modifying one is only changing that one >>> result = 'a' >>> print( result) [[1, 'a', 3], [1, 9, 3], [1, 9, 3], [1, 9, 3], [1, 9, 3]]
The same situation occurs when mutable objects are passed as arguments to functions or methods. This means that a function can change values outside of the function if the coding is not done carefully.
>>> my_list = [1, 2, 3, 4, 5] >>> def double_list(lst): ... for idx, item in enumerate(lst): ... lst[idx] = item * 2 ... return lst ... >>> double_list(my_list) [2, 4, 6, 8, 10] >>> my_list # my_list is also changed outside of function! [2, 4, 6, 8, 10]
The fix for the above situation would be to append to a different list and return that list. Or you could add the line:
# Add line near top of function lst = copy.copy(lst)
Post back if you have more questions. Good luck!!