Introduction to Python Programming - Session 5 Catchup

November 16, 2015
- Jamie Tanna (HackSoc 2015-16 General Secretary)

Lists, Glorious Lists

As we briefly touched upon last session, lists are a great way to work with multiple variables, without having separate variables assigned for each one. We’re also able to store different bits of data in them, such as mixed_list in the below example:

names=["Rich","Jamie","Luke","Harry","Gregor"]hair=["Brown","Red","Ginger","Green","Brown"]mixed_list=[1,"hello",1.235,12*10,("Hellooooo",123)]printnamesprinthairprintmixed_listfornameinnames:print"Our new name is",nameforhair_colourinhair:print"Our new hair colour is",hair_colour

Remember from last time that the syntax for lists is using square brackets, [ to start a list, ] to end it, and commas to separate each individual value.

In the first set of print statements, we print out the values of the lists in one go, which Python does with the same syntax as we use to create them.

In the second set of print statements, we are going to iterate through each value of the list. This is called a for loop, and the syntax makes it much easier for us to go through each element individually. The value of name is reset at each point in the loop with the value of the next element in the list.

Note: I may use the term array in place of the term list. For these tutorials, they are interchangeable - so please don’t be confused if I use either.

Exercises:

Create a for loop that iterates through mixed_list and prints out each element.

Accessing the List Elements Directly

Luckily we don’t always have to iterate through the whole list, but we can instead access the element at a given position.

Before we look at how, one point to always remember about working with lists is that they are zero-indexed (zero-indexed: instead of starting counting at one, we start at zero). As with all modern programming languages, we start counting from zero; there is no point wasting space in the computer’s memory to start counting from one like ‘normal’.

Therefore, if we wanted to access elements of the list, we would do something like:

names=["Rich","Jamie","Luke","Harry","Gregor"]print"The first name is",names[0]print"The second name is",names[1]print"The fourth name is",names[3]

Note that the syntax follows that of how we create lists - we use the square brackets.

Because of the way that we can access individual elements, we can also use a loop counter inside our for loop to access the elements directly, like so:

names=["Rich","Jamie","Luke","Harry","Gregor"]hair=["Brown","Red","Ginger","Green","Brown"]mixed_list=[1,"hello",1.235,12*10,("Hellooooo",123)]printnamesprinthairprintmixed_listloop_counter=0printnames[3]fornameinnames:hair_colour=hair[loop_counter]print"Hello my name is",name,"and I have",hair_colour,"hair"loop_counter=loop_counter+1

As we can see here, we’re iterating through the names list, and using our loop_counter to access the elements of hair_colour. But this isn’t ideal as we’re mixing accessing styles, which does not make sense. To clean this up, we’re going to access both through the loop counter, which will be generated with the Python function range. range is a really useful function which, given an integer, creates a list of the numbers up to, but not including, the given integer. For instance:

We use the temporary variables in the loop for readability, but we could just as simply used the list access syntax instead.

Note the += shorthand for incrementing our loop_counter.

Magic Numbers are the Devil

In the above code, we’ve hardcoded in the number 5 as the length of the list - this is a terrible idea, because every time we increase the size of the list, we need to remember to update the value stored there. Additionally, when reading back over the code we may not instantly work out what the 5 refers to. This is referred to as a magic number (magic number: “unique values with unexplained meaning”) and using magic numbers is very bad when maintaining code, and should instead be replaced by a variable which explains what it means, for instance:

As we can see, the choice of variable name makes it very easy to understand what the value indicates. However, we will still need to remember to update it as soon as we change the list. Therefore, we will instead use the len function, which gives us the length of a given list:

This version will then let us adapt to a changing list length much more easily, and means we don’t have to update our variable when the list changes. While this may seem trivial in this example, when we get to a larger program, we will have potentially tens of lists and variables to update, and it’ll get a bit too much to remember every time.

Reducing the Number of Lists

As we can see in our code, the names and hair lists are very tightly coupled - we will always have an entry in one for the other. Therefore, having two variables stored is not ideal. To get around this, we will use tuples, which we again briefly touched on last session, which are a data structure that allows us to store multiple values (be it two or two hundred) i.e. pairs of coordinates. In our example, we will pair a person’s name with their hair colour, as such:

There are a few things we’re doing here. Firstly, the syntax for a tuple is the same as a pair of coordinates - parentheses around the values, and commas separating them.

You will see there are two methods of accessing the tuple values - firstly, we capture the values in the same way as we get multiple return types from a function, just with the added parentheses. Secondly, we index into the tuple, in the same syntax as we index into lists. Both methods work identically, and are purely down to preference.

Exercises

Here we had a break for you to implement the following:

Take a name from the user

Check the list of people for their name

When you find their name, print out their hair colour

Bonus points: Error checking! What if there isn’t someone by that name?

The answer is intentionally not given, so you have to work to implement it yourself.

PyZork: The All-Star Spelling Conundrum

At the end of the session, we started to create a text-based adventure game. This is our last exercise before we move to Flask, and aims to summarise all the work we’ve done so far.

You can see below the initial skeleton (pun intended) for the game:

fromsysimportexitdefget_str_from_user(prompt):input=raw_input(prompt)input=str(input)returninputdefdead(why):print"You dead."print"..."print"How?",whyexit(0)defzombies():dead("You get eaten by zombies")defstart():print"You wake up in your room"print"You look down and notice a dirty rag on your foot"print"What will you do?"isInRoom=TruewhileisInRoom:# if# .. inprint""print"'pickup' the rag"print"turn on the 'lights'"print"go to 'sleep'"print"look for an 'exit'"inp=get_str_from_user("What will you do?")ifinp=="pickup":print"You gain one rag. Lucky you"elifinp=="lights":print"Well done /s"room_lights()elifinp=="sleep":zombies()elifinp=="exit":print"You're in the dark, you can't find an exit"defroom_lights():print"You can see a door"print"What will you do?"isInRoom=TruewhileisInRoom:print""print"'exit'"print"go to 'sleep'"inp=get_str_from_user("What will you do?")ifinp=="exit":# TODO where next?passstart()

Homework

Yes, you’ve been set homework this week! It’s to design and start to implement your own game, following the structure above. This will you a chance to get ahead, and make the session a lot easier, as we’ll be carrying on your work and finishing the game. Once finished, we’ll play them live!