Audio Version of this Post

Lists, or what python refers to as a list, is really just what most all other programming languages call “arrays”.

Here are some properties of lists:

  • Lists are mutable.

Unlike strings and tuples, which are immutable, the values at each index of a list can be changed and/or altered. The following example illustrates this:

list2 = [123]

list2[1:3]=[456,789]
print list2
[123,456,789]

So here, the last two indices (1 and 2) were changed from their string values to the three number values. It’s worth noting (for purposes of clarification) that in the above example, the three numbers (or three letters) are considered to be the one single value of that list index.

This shows the mutability of lists.

list2=['abc','def','ghi']
print list2
['abc','def','ghi']
list2[0]=123
print list2
[123,'def','ghi']

In the above example, the element value in the first index (the 0eth element) was changed from abc to 123. Additionally, you can combine the slice operator (illustrated next) to update a range of list values.

    • You can take slices of lists with the listname[startNumIndex:endNumIndex] method. For example. if
      list1 = ['a','b','c','d'] and I wanted just the last two indices, then>print (list1[2:4)
      >[‘c’,’d’]
    • The notation for that took me awhile to comprehend, because of the inclusion of the first 0eth index and the fact that the terminating index always is 1+ the index number. In the above list ‘c’ is indeed the 2eth index, but ‘d’ is the 3eth. The list slice method is non-inclusive for the terminating slice so it’s alwyays one less than that. You can exclude a number altogether as in list1[:2] which would include all the first element values up to the last minus one index. In this case,
      >print list1[:2]
      >['a','b']

      How and why is that? Well, again, omitting the first number means it includes all values up to the second number. In this case, the endNumIndex is 2, but the last number in a slice is always only inclusive to the previous number in the index, meaning it is exclusive to index value 2 (in this instance, ‘c’) and all values after it, so that slice returns the first two values of the list.
    • List elements can be deleted.

      In addition to “nulling” out a single or (with the slice operator) a range of elements, individual (or a range) of elements can be deleted with the del operator.


      >list3 = ["one","two","four"]
      >del list3[2]
      >print list3
      >["one","two"]

      the del command simply deleted the value at index 2 (in this case “four”).

Lists can be cloned.

Cloning a list does not directly involve a special operator nor command, but merely utilizes the slice operator to assign all values of a list to a new list:

>lista=[7,8,9]
>listb=lista[:]
>print listb
>[7,8,9]

And to show that each list is indeed referencing its own distinct set of elements in memory, here’s some sample code testing that out.


lista[2]="nine"
print lista
[7,8,'nine']
print listb
[7,8,9]

Indeed, the two list names, “lista” and “listb”, both point to their own individual set of indexed elements.

Lists can be aliased.
That’s fine and dandy but you may ask “Why not just do lista=listb?” Indeed, that would work in a way.

>lista=[7,8,9]
>listb=lista
>print listb
>[7,8,9]

But here’s where the change is apparent

>lista[1]=9000
>print lista
>[7,9000,9]
>print listb
>[7,9000,9]

That’s actually aliasing the list and superficially has the same result/appearance, but overall “aliasing” is different from “cloning”. A cloned list has it’s own unique set of elements, whereas two aliased lists share the same list of elements in memory. Ultimately the main difference between aliasing and cloning a list is that if you change the elements of an aliased list, it reflects in the other list, whereas changes to elements of one list do not effect the cloned list. Conclusively, aliased lists share one set of indexed elements whereas cloned lists each have their own unique set of indices and elements.

Another side note, if you redefine a list, it breaks any lists aliased to it, so:

>lista=[7,8,9]
>listb=lista
>print listb
>[7,8,9]
>lista=['seven','eight','nine']
print listb
[7,8,9]
print lista
['seven','eight','nine']

In the above code snippet, lista and listb are first aliased to each other, sharing the same index (of [7,8,9]), but then lista is reassigned to a new list; lista is said to be “initialized” (or, in this case, re-initialized). The result is the aliased nature of lista and listb are broken and then each list has its own set of elements.

    • A list can be nested.

      This is where things get slightly complex. A nested list can actually be assigned to one index of a pre-existing list. In other words, an entire list can be “one” element if it is assigned as such.

      listnest=["letters","numbers",[7,2,3.22]]
      print listnest
      ['letters','numbers',[7,2,3.22]]
      print listnest[2]
      [7,2,3.22]

      Here the 2eth index or third element of the listnest was actually an entirely additional list that contained three elements. When just the 2eth index (third element) is printed out the full nested list (composed of two ints and a float) returns.

      You can call a single element from a nested list by using double index call brackets []:


      listnest[2][2]
      3.22

      Matrices (a subset of ‘Lists can be nested’).
      Assigning a “matrix” to a list is really just using multiple nested lists. The only way in which a list actually resembles a matrix of elements is via nested lists. So to instantiate a “matrix” (really just multiple nested lists) one would use the following code.


      >>> matrixlist=[[1,2,3],['one','two','three'],['uno','dos','tres']]
      >>> matrixlist[2][2]
      'tres'
      >>> matrixlist[0][1]
      2

      One important thing to remember is that although the lists are nested, they’re considered each just a normal element and thus they require a comma separating them. If you try to implement

      >>> matrixlist=[[1,2,3]['one','two','three']['uno','dos','tres']]

      You will get a syntax error.

Lists can be combined with string functions (the magical fusion of lists and strings).

One string (module) to rule them, one string module to bind them (and separate them).
Okay going to town with cheesy puns of the string module.

Strings, if you recall, are immutable. But lists are not; lists are mutable. Using some (these are referencing only python 2.7) built-in functions of the string module, we can do some interesting things with strings.

Separate them (with an optional delimeter)
>>> import string
>>> song="Deck the halls with bows of holly"
>>> string.split(song)
['Deck', 'the', 'halls', 'with', 'bows', 'of', 'holly']
>>> songlist=string.split(song,"h")
>>> songlist
['Deck t', 'e ', 'alls wit', ' bows of ', 'olly']

Okay that may need some explaining.

      1. Line one imports the string module.
      2. Line two merely assigns a string (in this case 7 words of a lyric) to a variable.
      3. The third line splits those words using the default delimeter which is a space and returns the resulting list, consisting now of 7 elements.
      4. The fourth line splits the original variable “song” into a list of 5 elements, but the delimeter is now (with funky results) an “h”. This list is stored in the variable songlist. It’s useful to observe that by choosing a certain delimeter, you automatically eliminate that delimeter from the list of a “splitted” string.

Join them (with an optional delimeter)
song=”Deck the halls with bows of holly”
>>> string.join(song,"h")
'Dhehchkh hthhheh hhhahlhlhsh hwhihthhh hbhohwhsh hohfh hhhohlhlhy'
>>> string.join(song,"_")
'D_e_c_k_ _t_h_e_ _h_a_l_l_s_ _w_i_t_h_ _b_o_w_s_ _o_f_ _h_o_l_l_y'
>>> splitsong=string.split(song)
>>> string.join(splitsong,"___")
'Deck___the___halls___with___bows___of___holly'
>>>

Okay the first and second calls of string.join() joins the elements of the list with, respectively, the letter “h” and an underscore “_”. However, remember that strings are considered immutable lists (that have indices) of characters? Well, the original “song” string value was never stored and split, so string.join() looked at each individual letter of the string as a separate element! Before the third call of string.join() the “song” string has been split (with the default space delimeter) into a list of 7 elements (called splitsong) so now each of those seven elements (words previously separated via a space) are joined with the triple underscore delimeter “___”. Fa la la la la, la la la la. Jolly good!

Why Is this Important Again?

It’s important to be cognizant of which lists alias each other, when a list is re-initialized, and when a list is cloned (and thus possessing it’s own set of elements and indices) because all those different code situations change each list and corresponding indices differently depending on the aliased, cloned, or re-initialized situation!

See, aliased lists (like all lists) are indeed mutable, and here the second element at the 1eth index was changed from 8 to 9000 in lista, but since the lists are not cloned, but aliased, the same change (1eth element changed from 8 to 9000) reflected in listb. Aliased lists are the same list with different names. They point to the same index of elements in memory however. This is a subtle (but with more advanced programs), useful clarifying distinction.

Works Used
Downey and Meyers. How to Think Like a Computer Scientist.

About V.P.

meh meh.

Leave a comment