We have already seen lists and how they can be used. Now that you have some more background I will go into more detail about lists. First we will look at more ways to get at the elements in a list and then we will talk about copying them.
Here are some examples of using indexing to access a single element of a list:
>>>some_numbers = ['zero', 'one', 'two', 'three', 'four', 'five']>>>some_numbers[0]'zero'>>>some_numbers[4]'four'>>>some_numbers[5]'five'
All those examples should look familiar to you. If you want the first item in the list just look at index 0. The second item is index 1 and so on through the list. However what if you want the last item in the list? One way could be to use thelen() function likesome_numbers[len(some_numbers) - 1]. This way works since thelen() function always returns the last index plus one. The second from the last would then besome_numbers[len(some_numbers) - 2]. There is an easier way to do this. In Python the last item is always index -1. The second to the last is index -2 and so on. Here are some more examples:
>>>some_numbers[len(some_numbers) - 1]'five'>>>some_numbers[len(some_numbers) - 2]'four'>>>some_numbers[-1]'five'>>>some_numbers[-2]'four'>>>some_numbers[-6]'zero'
Thus any item in the list can be indexed in two ways: from the front and from the back.
Another useful way to get into parts of lists is using slicing. Here is another example to give you an idea what they can be used for:
>>>things = [0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, "Jack", "Jill"]>>>things[0]0>>>things[7]'Jill'>>>things[0:8][0, 'Fred', 2, 'S.P.A.M.', 'Stocking', 42, 'Jack', 'Jill']>>>things[2:4][2, 'S.P.A.M.']>>>things[4:7]['Stocking', 42, 'Jack']>>>things[1:5]['Fred', 2, 'S.P.A.M.', 'Stocking']
Slicing is used to return part of a list. The slicing operator is in the formthings[first_index:last_index]. Slicing cuts the list before thefirst_index and before thelast_index and returns the parts inbetween. You can use both types of indexing:
>>>things[-4:-2]['Stocking', 42]>>>things[-4]'Stocking'>>>things[-4:6]['Stocking', 42]
Another trick with slicing is the unspecified index. If the first index is not specified the beginning of the list is assumed. If the last index is not specified the whole rest of the list is assumed. Here are some examples:
>>>things[:2][0, 'Fred']>>>things[-2:]['Jack', 'Jill']>>>things[:3][0, 'Fred', 2]>>>things[:-5][0, 'Fred', 2]
Here is a (HTML inspired) program example (copy and paste in the poem definition if you want):
poem=["<B>","Jack","and","Jill","</B>","went","up","the","hill","to","<B>","fetch","a","pail","of","</B>","water.","Jack","fell","<B>","down","and","broke","</B>","his","crown","and","<B>","Jill","came","</B>","tumbling","after"]defget_bolds(text):true=1false=0## is_bold tells whether or not we are currently looking at## a bold section of text.is_bold=false## start_block is the index of the start of either an unbolded## segment of text or a bolded segment.start_block=0forindexinrange(len(text)):## Handle a starting of bold textiftext[index]=="<B>":ifis_bold:print"Error: Extra Bold"## print "Not Bold:", text[start_block:index]is_bold=truestart_block=index+1## Handle end of bold text## Remember that the last number in a slice is the index## after the last index used.iftext[index]=="</B>":ifnotis_bold:print"Error: Extra Close Bold"print"Bold [",start_block,":",index,"]",text[start_block:index]is_bold=falsestart_block=index+1get_bolds(poem)
with the output being:
Bold [ 1 : 4 ] ['Jack', 'and', 'Jill']Bold [ 11 : 15 ] ['fetch', 'a', 'pail', 'of']Bold [ 20 : 23 ] ['down', 'and', 'broke']Bold [ 28 : 30 ] ['Jill', 'came']
Theget_bold() function takes in a list that is broken into wordsand tokens. The tokens that it looks for are<B> which startsthe bold text and</B> which ends bold text. The functionget_bold() goes through and searches for the start and endtokens.
The next feature of lists is copying them. If you try something simple like:
>>>a = [1, 2, 3]>>>b = a>>>print b[1, 2, 3]>>>b[1] = 10>>>print b[1, 10, 3]>>>print a[1, 10, 3]
This probably looks surprising since a modification tobresulted ina being changed as well. What happened is that thestatementb = a makesb areference toa.This means thatb can be thought of as another name fora.Hence any modification tob changesa as well. Howeversome assignments don't create two names for one list:
>>>a = [1, 2, 3]>>>b = a * 2>>>print a[1, 2, 3]>>>print b[1, 2, 3, 1, 2, 3]>>>a[1] = 10>>>print a[1, 10, 3]>>>print b[1, 2, 3, 1, 2, 3]
In this caseb is not a reference toa since theexpressiona * 2 creates a new list. Then the statementb = a * 2 givesb a reference toa * 2 rather than areference toa. All assignment operations create a reference.When you pass a list as an argument to a function you create areference as well. Most of the time you don't have to worry aboutcreating references rather than copies. However when you need to makemodifications to one list without changing another name of the listyou have to make sure that you have actually created a copy.
There are several ways to make a copy of a list. The simplest thatworks most of the time is the slice operator since it always makes anew list even if it is a slice of a whole list:
>>>a = [1, 2, 3]>>>b = a[:]>>>b[1] = 10>>>print a[1, 2, 3]>>>print b[1, 10, 3]
Taking the slice[:] creates a new copy of the list. However itonly copies the outer list. Any sublist inside is still a referencesto the sublist in the original list. Therefore, when the listcontains lists, the inner lists have to be copied as well. You coulddo that manually but Python already contains a module to do it. Youuse thedeepcopy function of thecopy module:
>>>import copy>>>a = [[1, 2, 3], [4, 5, 6]]>>>b = a[:]>>>c = copy.deepcopy(a)>>>b[0][1] = 10>>>c[1][1] = 12>>>print a[[1, 10, 3], [4, 5, 6]]>>>print b[[1, 10, 3], [4, 5, 6]]>>>print c[[1, 2, 3], [4, 12, 6]]
First of all notice thata is a list of lists. Then noticethat whenb[0][1] = 10 is run botha andb arechanged, butc is not. This happens because the inner arraysare still references when the slice operator is used. However withdeepcopyc was fully copied.
So, should I worry about references every time I use a function or=? The good news is that you only have to worry aboutreferences when using dictionaries and lists. Numbers and stringscreate references when assigned but every operation on numbers andstrings that modifies them creates a new copy so you can never modifythem unexpectedly. You do have to think about references when you aremodifying a list or a dictionary.
By now you are probably wondering why are references used at all? Thebasic reason is speed. It is much faster to make a reference to athousand element list than to copy all the elements. The other reasonis that it allows you to have a function to modify the inputted listor dictionary. Just remember about references if you ever have someweird problem with data being changed when it shouldn't be.