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

Why does this not sort?

When I used this code . . .

sorted_things = favorite_things
sorted_things.sort()

. . . it told me not to sort favorite_things, but I was sorting sorted_things.

When I used this code it worked:

sorted_things = favorite_things[:]
sorted_things.sort()

What did the first code not work? Why is the [:] necessary?

1 Answer

Hi Henry,

favorite_things is a reference to a mutable object, in this case a list.

When Python evaluates this line:

sorted_things = favorite_things

It makes sorted_things a reference to the same mutable object.

Accordingly, when call sort() on sorted_things, Python is mutating the corresponding object. Since favorite_things still points to the same object, checking the value of favorite_things will return the sorted version.

When you create a list slice, you are creating a new object. So, if you have the following:

>>> my_list = [1, 2, 3, 'foo', 'bar', 'baz', True, False]
>>> new_list = my_list[3:6]
>>> my_list
[1, 2, 3, 'foo', 'bar', 'baz', True, False]
>>> new_list
['foo', 'bar', 'baz']

In effect, by slicing, you have copied the specified items from one list into a new list. Since these lists are different objects, you can mutate them independently:

>>> my_list.reverse()
>>> my_list
[False, True, 'baz', 'bar', 'foo', 3, 2, 1]
>>> new_list.sort()
>>> new_list
['bar', 'baz', 'foo']

When creating a slice, you don't have to specify the start and end of the slice range. If you leave the value before the colon blank, it will slice from the beginning of the list to whatever the specified end value is. Similarly, if you leave the value after the colon blank, it will slice from the specified start value to the end of the list. Thus if you leave both values blank, it will slice from the beginning of the list to the end:

>>> my_list
[False, True, 'baz', 'bar', 'foo', 3, 2, 1]
>>> my_list[:4]
[False, True, 'baz', 'bar']
>>> my_list[4:]
['foo', 3, 2, 1]
>>> my_list[:]
[False, True, 'baz', 'bar', 'foo', 3, 2, 1]

This means that when you want to copy the values of a list from one variable to another, instead of passing a reference to the object, you can assign a slice of the original list to the new variable. And, based on the way slices work, if you want to copy the whole list from one variable to another, you create a slice that represents the whole original list (i.e., [:]).

Hope that clears things up for you,

Cheers

Alex