Python is No Good for Mortality Rates

Here we are at the uptick in the Covid 19 pandemic. There are many sources of data which list infections and deaths as a result of the virus. It’s very tempting to want to put your Python skills to use and crunch some numbers on the infection. By and large, go for it, but one thing I’d ask you not to do is to try to calculate a “mortality rate”. This is not because Python can’t do division but, rather, working this number out is conceptually pretty tricky. It’s something that epidemiologists need to get a lot of training in to do correctly.  You can’t just take the deaths column and divided it by the infected column because the two numbers are not properly related. For example:

  • Testing is incomplete. There is a shortage of test kits where I am. So, if you present with symptoms you will not get tested unless you meet the testing protocol – that is: have you been overseas in the last 14 days; or have you been in contact with a known Covid19 case. This testing protocol means that (most) community transmission of the virus hereabouts is not included in the numbers.
  • There is evidence to believe that a large cohort of those infected are asymptomatic. That is, they have no symptoms or very mild symptoms. If that’s the case, then there is a cohort of infected people who don’t feel unwell, so they don’t get tested and are, also, omitted from the infection numbers.

These factors will mean that naive division of the reported numbers will inflate the mortality rate, making it seem worse, possibly much worse, than it really is (the Economist argues [paywall] that places with extensive testing have much lower death rates – by a factor of 5 or so – simply because they are identifying more of those infected).

Ideally, if you’re going to publish these numbers make it clear what their limitations are.

PS: The Diamond Princess is probably the only cohort to have reliable infection numbers, since everyone was tested before leaving the ship. However, their mortality rate shouldn’t be used as they’re not a representative sample (ie mostly older people who are fit enough and wealthy enough to go on a cruise).

PPS: Further virus related stuff (eg on lag) to be posted on my other not actually python blog.

3: Lists

Book ref: Project 6 (pg 149ff)

Python 2.7: Mostly same, see note below

See also: Python 3/Project 6 post

Source: Python for kids

You have learned how to give a literal a name, like this:

name = "Brendan"


age = 8

Giving it a name allowed you to identify the value in the future. While strictly incorrect, people sometimes say that you are “storing” the value in the name – and they even call the name a varable.
There is a bit of a problem with this because you have to name each of the values you have one at a time.
Imagine you had a group of 3 people and your teacher told you you had to write a program to store all of their ages and to find their average age. Let’s say their ages are 8, 13 and 25. How would you do it?

Well, you could try something like this:

person1_age = 8
person2_age = 13
person3_age = 25

average_age = (person1_age+person2_age+person3_age)/3

print("average age is ", average_age)

That works,* but… The next day your teacher comes and tells you that someone else has joined and you now need to include their age (17) in your program. How do you do it?

Well, you could do this:

person1_age = 8
person2_age = 13
person3_age = 25
person4_age = 17 

average_age = (person1_age+person2_age+person3_age+person4_age)/4

print("average age is ", average_age)

To add a single extra age to your calculation you made three additions. You added a line person4_age = 17 to store the age and then you changed the average_age line to add that new variable to the calculation and also you need to keep track of the number of people and change the divided by 3 to divided by 4. The next day another person, aged 11 comes along, and you use the same way of dealing with the problem. You end up with this code:

person1_age = 8
person2_age = 13
person3_age = 25
person4_age = 17
person5_age = 11

average_age = (person1_age+person2_age+person3_age+person4_age+person5_age)/5

print("average age is ", average_age)

I hope that you’re dreading any more people arriving – but it can get much worse without any more people! Imagine your teacher asks you to write code to print out the ages in order from smallest to largest. The only way you can do that with this code is to sort the ages yourself and then print the variables in the correct order. What’s the point of learning Python if you have to do the calculations yourself?

Luckily Python has a way of storing these values that makes doing things like this easy. It’s called a list. You can create a list of values by putting a comma between each pair of values and surrounding the whole lot by square brackets []. For example, say your values are 1 and 4, you would create a list like this:

>>> [1, 4]
[1, 4]

There’s a comma in between them and they’re surrounded by square brackets []. You can add more entries in the list by adding a comma then the new entry:

>>> [1, 4, 8]
[1, 4, 8]

A list can be empty – contain no values. It looks like this:

>>> []

A list with only one value looks like this (no commas):

>>> [1]

You name a list in the same way you name any other value:

>>> a_list = [1, 2, 3, 4]

So, for the ages you had above you could make a list like this:

>>> ages = [8, 13, 25, 17, 11]

In Python lists can sort themselves. You just add .sort() to the name of the list and it will become sorted. Like this:

>>> ages.sort()
>>> ages
[8, 11, 13, 17, 25]

Python calls the number of entries in a list its length. To get this number you use the len() facility. Like this:

>>> len(ages)

This says that the list called ages has 5 entries in it (count them yourself to confirm it’s correct).

You can add all of the entries in a list by using the sum() facility.

>>> sum(ages)

So, you can simplify your average age program above like this:

ages = [8, 13, 25, 17, 11]
print ("average age is ", sum(ages)/len(ages))

Amazing? It’s certainly much simpler. Test that it works for any number of ages by adding and removing ages to the ages list. If the age list is empty you’ll break the code. Try it and see.

You can tackle the requirement to put them in order very easily as well:

ages = [8, 13, 25, 17, 11]
print ("average age is ", sum(ages)/len(ages))
print ("ages in order are: ", ages)

You didn’t notice, but the .sort() facility on the list ages is unusual because it changes the list itself. In Python it is more usual for these facilities to leave the thing they are working on unchanged and to return a new value for you. Normally you can count on the thing you started with not changing.

* Note: as you learned in Python for Homework Python 2.7 carries out division differently from Python 3. For Python 2.7 it is better to use float(3) or 3.0, otherwise Python will round the result. See Python for Homework for more details.

3: Comments

Book ref: Project 4 (pg 95ff)

Python 2.7: Same

In this post you’re going to learn how to write code that Python ignores. Does that seem odd?
What would be the point of writing code and then deliberately not using it? It turns out that
there are two important times when you would prefer that Python did not execute your code:

  • comments, which you’ll be learning about in this post; and
  • debugging, which you’ll learn about later.

There are two main ways to make a comment in Python. The first is to put a hash mark (#) in
front of the comment. Here is an example:

>>> # This code does nothing

Hopefully you can see that the text with the # in front of it was ignored by the Python interpreter.
You can see that this is the case by trying it without the # and seeing what happens.

>>> This code doesn't do anything
SyntaxError: invalid syntax

Without the # Python tries to run the comment as if it was Python code – and, of course, fails.

Whenever you are not sure about how something works in Python open up a Python console and give it a try and see what happens. Often, if there is a mistake Python will give you an error message that will help you work out how to do it correctly.

The second way of making a comment is by putting triple double quotes (“””) on both sides of the comment. Like this:

>>> """ This code does nothing"""
" This code does nothing"

You can see from the print out that while the # comment above really did nothing, this code has done something – it’s printed out the content of the comment. It did this because it has created a string literal but hasn’t given it a name. In practical terms though, the code has done nothing. The only reason that it has printed out the comment is because you are running the Python console. If you ran this from a file (see the python idle post for more info), nothing would be printed.

Technically the other ways of making string literals will work as comments, but the accepted way of doing it is by using triple double quotes.

What are comments for?

You use comments mainly to explain to someone else what your code is doing (try to imagine that you’re trying to explain your code to your parents). As such, comments should explain why, not describe how. This is a bad comment:

>>> a = a*2 # multiply a by 2

This is a bad comment because it simply repeats in words what the code is doing. Anybody reading the code can work that out for themselves, so it’s not adding anything. It is better to explain why the code is doing whatever it is doing.

This might be a better comment:

>>> a = a*2 # the next section of code below needs a to be even

In this code, the comment is explaining why a is being multplied by 2. That is, to make sure that a is an even number. We can’t tell from this why it’s important for a to be even, but we can tell why the code is doubling a.

Explanatory comments like these turn out to be very important. That’s because you often need to come back to code that you’ve written a long time ago (like last month). If you don’t have comments explaining why the code is doing what it’s doing it can be very difficult to understand what is going on. So, it’s difficult to reuse the code for other projects, or two tweak the code to cater to new circumstances.

In general, comments are a good thing. The more comments the better. That said, you can get too much of a good thing and there is a point where you have too many. Exactly how many comments are too many is hard to say. Best way is to write comments and get a feel for it yourself.

3: Getting Help

Book ref: Project 1 (pg 24ff)

Python 2.7: Same

See also: Python 3/Project 4 post

Python 3 comes with its own help facility. To use it, you simply type:

>>> help()

Welcome to Python 3.4's help utility!

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics".  Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".

Note: you have to include the brackets help(). Just help won’t work:

>>> help
Type help() for interactive help, or help(object) for help about object.

As the text says, once you’re in the help service. To leave you type quit and press Enter.

You can get help on a specific feature by typing that feature at the help> prompt. If I type print and press Enter it tells me:

Help on built-in function print in module builtins:

    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

On my system, this is not printed below the Python prompt. Rather, it is specially formatted (by a thing called a “pager”). To get back to the help> prompt I have to press the Q key.

The next place to look for help is in Python’s online documentation. That may be a little intimidating at the moment, but just go to it slowly. You’ll start to learn your way around it. One of the problems with learning Python 3 is that it is being continuously improved, so with each new version (I have version 3.4 installed, but the most recent version as at the time I am writing this is version 3.6) the documentation changes. Ideally, you’ll chose the version of the documentation that matches the version of Python you have installed on your computer. The good news is that for the stuff you’re learning things are unlikely to change for the foreseeable future.

Python 2.7 Notes: the same help facility is in Python 2.7.

3: Import this!

Book ref: Project 3 (pg 78ff)

Python 2.7: Same

>>> import this

Do it to learn something about the Zen of Python.

3: Using Python IDLE

Book ref: Project 4 (pg 84ff)

Python 2.7: Same

See also: Python 3/Project 4 post

You have started this new batch of tutorials working with the Python (Command Line) program. Python (Command Line) looks black and a bit ugly. It’s also a bit old fashioned in how it lets you interact with it.


It’s important to know about Python (Command Line) because it’s the easiest way to do something quickly in Python. For example, if I want to quickly check how something works in Python I will open up a Python command line and check it. So, you start out with it because it’s something you’re going to use for the rest of your Python programming days.

The command line has some limitations. Maybe the biggest of those is that it doesn’t let you save anything, but never fear! Python has an answer to that in IDLE. IDLE is a program that helps you write Python programs. One of the many things it can do is to allow you to save your programs to use them later. Open up your menu’s search bar and type “Python”. Click the entry that says IDLE(Python GUI). You should get a window that looks like this (the words might be different):


See how the title of the window says Python 3.4.5 Shell? It can do pretty much everything the Python (Command line) shell can do. However, that’s not where you can save your code! Instead, you need to open a new file. Click the “File->New File” menu item (or type Ctrl+N):


It’ll open up a new window like this:


Type your code in there:

print("Hello world!")


and press Ctrl+S to save it. You’ll get a dialog box that asks you for a name to save it under. This is naming your Python file, much like you might name a word processing document or image that you create. In this case call it When saving your code, add “.py” to the end of the file name. Finally, press F5. Pressing F5 is what runs your code.

In the Shell Window you’ll get something that says “== RESTART:” and some other guff. Then, after that, it’ll show you the output of the program you saved:

Hello world!

Notice that IDLE gives different colors to different parts of your code? Try to work out what each of the colors means. IDLE has a lot of different features, project 4 of my book has more details, some of which are listed in the Python 3/Project 4 post.

3: Conditionals/if and Code Blocks

Book ref: 70ff

Python 2.7: Same, see earlier post

Note: this tutorial will be easier if you use Python-IDLE, not Python (Command Line).

So far, the programs you’ve written have gone straight from top to bottom, without skipping any lines. There are times though, when you do want a line to run only some of the time. For example, if you wrote a game, you’d only want one of these two lines of code to run:

print("Congratulations, you win!!!") 
print("Sorry, you lose.")

In fact, you’d want your code to look something like:

if player wins:
     print("Congratulations, you win!!")
     print("Sorry, you lose.")

Python isn’t quite that much like English, but it’s pretty close. In Python you can do this by using the if and else (not otherwise) keywords, like this:

player_wins = True

if player_wins:
    print("Congratulations, you win!!")
    print("Sorry, you lose.")

You see I’ve changed the two English words player wins to a single Python name player_wins. When you run this code, you get this output:

Congratulations, you win!!

If you change the line

player_wins = True


player_wins = False

(try it) then this is printed:

Sorry, you lose.

You need to remember that player_wins is just the name you’re using to store a value, the program can’t tell whether the player has won or lost. You need to set the value beforehand. You also need to notice that player_wins takes only two values – True and False (True and False are special values in Python, but you can take them as having their English meanings).

The if keyword needs to be followed by something that is either True or False. It could be a variable that holds one of those values or it could be an expression (see below) that evaluates to them. After “that something” you put a colon. The colon tells Python that a new code block is about to start. On the next line the code in the code block is indented. This indenting is important. Python will complain if the code is not indented (try it). If you want more things to happen, then you can put in more lines of code, as long as they’re all indented at the same level – that is, they have the same number of spaces in front of them (try 4 spaces in front). When you do more Python you’ll discover that you can put code blocks within code blocks – but that’s for later.

After the code block comes another keyword, else, followed by a colon and another code block. The else keyword serves the function of word otherwise in my mock code above. It is run if the if isn’t. After the else is another code block. This is indented like the first one and, like the first one, can contain more lines of code, as long as they are all indented with the same number of spaces in front of them.

Visually indented code blocks are one of Python’s great programming features. Most languages have code blocks, but few of them require them to be shown visually with indents. This makes Python programs easier to read and follow.

If you don’t have alternative code that is to be run if the conditional is not True, then you can leave out the else: and its code block. So, if you want to say Happy Birthday if it’s someone’s birthday, but nothing if it’s not, you could do something like this:

players_birthday = False

if players_birthday:
    print("Happy Birthday!")

When you run this code, it doesn’t print anything, because you’ve set players_birthday = False and have not included an else block. Set players_birthday = True and see what happens.


Rather than setting a value of True or False expressly, you can include a comparison. Python has a lot of comparisons but the main ones are == (equal- note the two equal signs together, not one), > (greater than) and < (less than). Here are some of them in action:

>>> 1 == 1
>>> 1 == 2
>>> 1 > 2
>>> 1 < 2

See how they give either a True or False result? Try some yourself. Make sure you know the difference between 1 = 2 and 1 == 2.

Going back to our earlier example, rather than having a name player_wins, you’re probably more likely to have something like players_score. You can then compare the score against a winning score and print your message. For example, if they players_score is 100 and a score of greater than 90 is a win you could code this:

players_score = 100

if players_score > 90:
    print("Congratulations, you win!!")
    print("Sorry, you lose.")

Run it, then change players_score = 90 and run it again.