Learning Python Part 3

Using lists we organize and categorize ourselves and the environment around us. In Python lists are essentially a container of sequenced objects that are alike in nature. You are not restricted to having lists of only a single data type, however it is often not seen as very intuitive to use different types in a list.

Lists like strings are a sequence type which really means that we can use an index to access the data, we’ll have a look at slicing which is a feature of sequence types, allowing us to get portions of data instead of a singular item.

Basic Manipulation

Lists can be defined using box brackets [] and items are seperated by a comma ,.

empty_list = []
numbers = [5, 12, 13, -1]
names = [
    "Joe",
    "Tom",
    "Bob"
]
mixed = [1, "1", 2, "Joe"]

To get a specific item from the list, we can use an index value. Using an index value that does not exist will however throw an error.

print(names[0])
print(names[3])
> Joe
> IndexError: list index out of range

We can remove items from the list by using the del operator.

del names[1]
print(names)
> ["Joe", "Bob"]

Even though both strings and lists are sequence types, a string is immutable and the del operator will throw an error.

word = "Hello"
del word[1]
> TypeError: <str> object does not support item deletion

We are going to need to be able to add to our list as well, we can do so using the + operator.

names = names + ["Peter", "Jane"]
print(names)
> ["Joe", "Bob", "Peter", "Jane"]

Methods vs Functions

Let’s quickly talk about the difference between methods and functions. Methods are part of an object and act on an object while functions are stand alone operations and take on arguments.

object.method()   # this would be a method
function(object)  # this would be a function

List Methods

List objects have several methods available we will cover some of the more common options.

We can add to our list using the append method.

names.append("Sarah")
print(names)
> ["Joe", "Bob", "Peter", "Jane", "Sarah"]

The append method only adds one item at a time, when we need to add a range of items we can use the extend method.

names.extend(["Lisa", "Zack"])
print(names)
> ["Joe", "Bob", "Peter", "Jane", "Sarah", "Lisa", "Zack"]

We can also remove from our list using the remove method. The remove method will remove the first occurence of the item in the list.

names.remove("Peter")
print(names)
> ["Joe", "Bob", "Jane", "Sarah", "Lisa", "Zack"]

Say we want to sort our list of names, we can use the sort method.

names.sort()
print(names)
> ["Bob", "Jane", "Joe", "Lisa", "Sarah", "Zack"]

We can add an item to a specific location using the insert method.

names.insert(1, "Chloe")
print(names)
> ["Bob", "Chloe", "Jane", "Joe", "Lisa", "Sarah", "Zack"]

Built-in Functions

The min function will return the smallest item in the list.

print(min(names))
> Bob

Similarly max will return the largest item in the list.

print(max(names))
> Zack

The sum function will return the items of the list added together, however it is not valid for strings

numbers = [1,2,3]
print(sum(numbers))
print(sum(names))
> 6
> TypeError: unsupported operand type(s) for +: 'int' and 'str'

The len function will return the number of items in the list. Unlike indexes the len function is not zero based.

print(len(names))
print(len(numbers))
> 7
> 3

Slicing

Slicing is really powerful once you are familiar with it. It allows you to modify your list in portions or slices.

The slicing syntax is as follows object[start:end:step]. The step argument is optional and we’ll talk about it a little later, for now let’s print our list using slicing syntax.

print(names[:])
> ["Bob", "Chloe", "Jane", "Joe", "Lisa", "Sarah", "Zack"]

Now say that we want the last three names in the list? Let’s provide a start position using the index value 4

print(names[4:])
> ["Lisa", "Sarah", "Zack"]

Say we want to get the first three names from our list? Let’s provide a end position using the index value of 3

print(names[:3])
> ["Bob", "Chloe", "Jane"]

Say we want all the names except the first two names and last two names?

print(names[2:-2])
> ["Jane", "Joe", "Lisa"]

Notice how we used -2 as a position? This indicates that it is the index value calculated from the end of the list. This concept can be used for all the indexing operations we’ve looked at up until now, including indexing in string objects.

It is important to know that the slicing start argument is inclusive and the end argument is exclusive. What does this mean? Let’s try and get Jane and Joe from the list.

print(names[2])
print(names[4])
print(names[2:4])
> Jane
> Lisa
> ["Jane", "Joe"]

Notice how Jane was included but Lisa was not. This is what is what is meant by inclusive and exclusive.

Now let’s try and get every second or third name in the list using the step argument.

print(names[::2])
print(names[::3])
> ["Bob", "Jane", "Lisa", "Zack"]
> ["Bob", "Joe", "Zack"]

We can provide a negative value for the step argument, which would also reverse the list.

print(names[::-1])
print(names[::-2])
> ['Zack', 'Sarah', 'Lisa', 'Joe', 'Jane', 'Chloe', 'Bob']
> ['Zack', 'Lisa', 'Jane', 'Bob']

We can do some interesting things though, for example we can replace a slice with something completely new. Let’s replace Jane and Joe with a new list of people.

names[2:4] = ["Theo", "Mandy", "Arnold", "Kim"]
print(names)
> ['Bob', 'Chloe', 'Theo', 'Mandy', 'Arnold', 'Kim', 'Lisa', 'Sarah', 'Zack']

Something to note is that the slice will return an entirely new list and not modify the existing list at all.

Multiple dimensions

We can create multiple dimension arrays as well, this really means that arrays are nested inside arrays. A common occurence of this is a 2d matrix.

array0 = [1, 2, 3]
array1 = [4, 5, 6]
array2 = [7, 8, 9]
arrays = [array0, array1, array2]

Accessing the items are much the same as before by providing an index.

print(arrays[1])
> [4, 5, 6]

And getting a specific nested item like 5 would look like this

print(arrays[1][1])
> 5

We can also modify items just like before with the newer syntax

arrays[1][1] = "MODIFIED"

print(array1)
print(arrays)
> [4, "MODIFIED", 6]
> [[1, 2, 3],[4, "MODIFIED", 6],[7, 8, 9]]

There is no limit to how many dimensions your array can have, however it is uncommon to go beyond two dimensions. It becomes extremely complicated to maintain a mental model of what is happening in your code.

Reference Items

Lists unlike strings are not immutable and use a reference that points to the original object. This means that we can change the original object and it would reflect in the list as well and visa versa.

Let’s say we have a list of chores.

chores = ["Takeout trash", "Feed animals", "Water plants"]

And we need to do these same chores every few days of the week.

#       Mon     Thu     Sat
week = [chores, chores, chores]

You become environmentally aware and decide to recycle your trash.

chores[0] = "Recycle Trash"
print(week)
> [["Recycle Trash", "Feed animals", "Water plants"],
   ["Recycle Trash", "Feed animals", "Water plants"],
   ["Recycle Trash", "Feed animals", "Water plants"]]

Notice how the value changed in all the items in the array. That is because of the reference to the chores variable which we modified.

What if we wanted to only change a specific occurence? We will then want to change the way we create our week list.

A little earlier, I said that slicing returns an entirely new array, lets use that to create unique copies.

week = [chores[:], chores[:], chores[:]]

And now let’s do laundry on saturday instead of watering plants.

week[2][2] = "Laundry"
print(week)
> [["Recycle Trash", "Feed animals", "Water plants"],
   ["Recycle Trash", "Feed animals", "Water plants"],
   ["Recycle Trash", "Feed animals", "Laundry"]]

This brings us to the end of lists in python. Hope you enjoyed it! Don’t hesitate to get in contact with me on any of the platforms provided at the bottom of the page.