This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
The first formula we shall consider concerns the vertical motion of a ball thrown up in the air. From Newton's second law of motion one can set up a mathematical model for the motion of the ball and find that the vertical position of the ball, called \( y \), varies with time \( t \) according to the following formula: $$ \begin{equation} y(t) = v_0t - \frac{1}{2}gt^2\tp \tag{1} \end{equation} $$ Here, \( v_0 \) is the initial velocity of the ball, \( g \) is the acceleration of gravity, and \( t \) is time. Observe that the \( y \) axis is chosen such that the ball starts at \( y=0 \) when \( t=0 \). The above formula neglects air resistance, which is usually small unless \( v_0 \) is large, see Exercise 11: Compute the air resistance on a football.
To get an overview of the time it takes for the ball to move upwards and return to \( y=0 \) again, we can look for solutions to the equation \( y=0 \): $$ \begin{equation*} v_0t - \frac{1}{2}gt^2 = t(v_0 - \frac{1}{2}gt) =0 \quad\Rightarrow\quad t=0\hbox{ or }t=2v_0/g\tp\end{equation*} $$ That is, the ball returns after \( 2v_0/g \) seconds, and it is therefore reasonable to restrict the interest of (1) to \( t\in [0, 2v_0/g] \).
Our first program will evaluate (1) for a specific choice of \( v_0 \), \( g \), and \( t \). Choosing \( v_0=5 \hbox{ m/s} \) and \( g=9.81 \hbox{ m/}\hbox{s}^2 \) makes the ball come back after \( t=2v_0/g\approx 1\hbox{ s} \). This means that we are basically interested in the time interval \( [0,1] \). Say we want to compute the height of the ball at time \( t=0.6 \hbox{ s} \). From (1) we have $$ \begin{equation} y = 5\cdot 0.6 - \frac{1}{2}\cdot 9.81 \cdot 0.6^2 \tag{2} \end{equation} $$ This arithmetic expression can be evaluated and its value can be printed by a very simple one-line Python program:
print 5*0.6 - 0.5*9.81*0.6**2
The four standard arithmetic operators are written as +
, -
, *
,
and /
in Python and most other computer languages. The
exponentiation employs a double asterisk notation in Python, e.g.,
\( 0.6^2 \) is written as 0.6**2
.
Our task now is to create the program and run it, and this will be described next.
A computer program is just a sequence of instructions to the computer, written in a computer language. Most computer languages look somewhat similar to English, but they are very much simpler. The number of words and associated instructions is very limited, so to perform a complicated operation we must combine a large number of different types of instructions. The program text, containing the sequence of instructions, is stored in one or more files. The computer can only do exactly what the program tells the computer to do.
Another perception of the word program is a file that can be run ("double-clicked") to perform a task. Sometimes this is a file with textual instructions (which is the case with Python), and sometimes this file is a translation of all the program text to a more efficient and computer-friendly language that is quite difficult to read for a human. All the programs in this document consist of short text stored in a single file. Other programs that you have used frequently, for instance Firefox or Internet Explorer for reading web pages, consist of program text distributed over a large number of files, written by a large number of people over many years. One single file contains the machine-efficient translation of the whole program, and this is normally the file that you double-click on when starting the program. In general, the word program means either this single file or the collection of files with textual instructions.
Programming is obviously about writing programs, but this process is more than writing the correct instructions in a file. First, we must understand how a problem can be solved by giving a sequence of instructions to the computer. This is one of the most difficult things with programming. Second, we must express this sequence of instructions correctly in a computer language and store the corresponding text in a file (the program). This is normally the easiest part. Third, we must find out how to check the validity of the results. Usually, the results are not as expected, and we need to a fourth phase where we systematically track down the errors and correct them. Mastering these four steps requires a lot of training, which means making a large number of programs and getting the programs to work.
There are three alternative types of tools for writing Python programs:
Based on teaching this and previous books to more than 3000 students, my recommendations go as follows.
gnome-terminal
is recommended).PATH
, it will be easier
in the long run to access Python in Ubuntu through a virtual machine.I assume that you have made a decision on how to access Python, which dictates whether you will be writing programs in a text editor or in an IPython notebook. What you write will be the same - the difference lies in how you run the program. the document How to access Python for doing scientific computing [1] briefly describe how to write programs in a text editor, run them in a terminal window or in Spyder, and how to operate an IPython notebook. I recommend taking a look at that material before proceeding.
Open up your chosen text editor and write the following line:
print 5*0.6 - 0.5*9.81*0.6**2
This is a complete Python program for evaluating the formula
(2). Save the line to a file with name ball1.py
.
The action required to run this program depends on what type of tool you use for running programs:
ball1.py
is located
and type python ball1.py
python ball1.py
command in a terminal windowSuppose you want to evaluate (1) for \( v_0=1 \) and \( t=0.1 \). This is easy: move the cursor to the editor window, edit the program text to
print 1*0.1 - 0.5*9.81*0.1**2
Run the program again in Spyder or re-execute the cell in an IPython
notebook. If you use a plain text editor, always remember to save the
file after editing it, then move back to the terminal window and run
the program as before:
Terminal> python ball1.py
0.05095
The result of the calculation has changed, as expected.
We use the prompt Terminal>
in this document to indicate
commands in a Unix or DOS/PowerShell terminal window. The text
following the Terminal>
prompt must be a valid operating
system command.
You will likely see a different prompt in the terminal window on your machine,
perhaps something reflecting your username or the current folder.
Even though a program is just a text, there is one major difference between a text in a program and a text intended to be read by a human. When a human reads a text, she or he is able to understand the message of the text even if the text is not perfectly precise or if there are grammar errors. If our one-line program was expressed as
write 5*0.6 - 0.5*9.81*0.6^2
most humans would interpret write
and print
as the same
thing, and many would also interpret 6^2
as \( 6^2 \).
In the Python language, however, write
is a grammar error and
6^2
means an operation very different from the exponentiation
6**2
.
Our communication with a computer through
a program must be perfectly precise without a single grammar
or logical error. The famous computer scientist Donald Knuth put it this
way:
Programming demands significantly higher standard of accuracy. Things don't simply have to make sense to another human being, they must make sense to a computer. Donald Knuth [3] (p. 18), 1938-.That is, the computer will only do exactly what we tell it to do. Any error in the program, however small, may affect the program. There is a chance that we will never notice it, but most often an error causes the program to stop or produce wrong results. The conclusion is that computers have a much more pedantic attitude to language than what (most) humans have.
Now you understand why any program text must be carefully typed, paying attention to the correctness of every character. If you try out program texts from this document, make sure that you type them in exactly as you see them in the document. Blanks, for instance, are often important in Python, so it is a good habit to always count them and type them in correctly. Any attempt not to follow this advice will cause you frustrations, sweat, and maybe even tears.
We should always carefully control that the output of a computer program is correct. You will experience that in most of the cases, at least until you are an experienced programmer, the output is wrong, and you have to search for errors. In the present application we can simply use a calculator to control the program. Setting \( t=0.6 \) and \( v_0=5 \) in the formula, the calculator confirms that 1.2342 is the correct solution to our mathematical problem.
When we want to evaluate \( y(t) \) for many values of \( t \), we must modify
the \( t \) value at two places in our program. Changing another
parameter, like \( v_0 \), is in principle straightforward, but in
practice it is easy to modify the wrong number. Such modifications
would be simpler to perform if we express our formula in terms of
variables, i.e., symbols, rather than numerical values. Most
programming languages, Python included, have variables similar to the
concept of variables in mathematics. This means that we can define
v0
, g
, t
, and y
as variables in the program, initialize the
former three with numerical values, and combine these three variables
to the desired right-hand side expression in (1),
and assign the result to the variable y
.
The alternative version of our program, where we use variables, may be written as this text:
v0 = 5
g = 9.81
t = 0.6
y = v0*t - 0.5*g*t**2
print y
Variables in Python are defined by setting a name
(here v0
, g
, t
, or y
) equal to
a numerical value or an expression involving already defined variables.
Note that this second program is much easier to read because it is
closer to the mathematical notation used in the formula
(1). The program is also safer to modify, because
we clearly see what each number is when there is a name associated
with it. In particular, we can change t
at one place only (the
line t = 0.6
) and not two as was required in the previous
program.
We store the program text in a file ball2.py
. Running the program
results in the correct output 1.2342.
Introducing variables with descriptive names, close to those in the
mathematical problem we are going to solve, is considered important
for the readability and reliability (correctness) of the program.
Variable names can contain any lower or upper case letter, the numbers
from 0 to 9, and underscore, but the first character cannot be a
number. Python distinguishes between upper and lower case, so X
is
always different from x
. Here are a few examples on alternative
variable names in the present example:
initial_velocity = 5
acceleration_of_gravity = 9.81
TIME = 0.6
VerticalPositionOfBall = initial_velocity*TIME - \
0.5*acceleration_of_gravity*TIME**2
print VerticalPositionOfBall
With such long variables names, the code for evaluating the
formula becomes so long that we have decided to break it into
two lines. This is done by a backslash at the very end of the line
(make sure there are no blanks after the backslash!).
In this document we shall adopt the convention that variable names have
lower case letters where words are separated by an
underscore. Whenever the variable represents a mathematical symbol, we
use the symbol or a good approximation to it as variable name. For
example, \( y \) in mathematics becomes y
in the program, and \( v_0 \) in
mathematics becomes v0
in the program. A close resemblance between
mathematical symbols in the description of the problem and variables
names is important for easy reading of the code and for detecting
errors. This principle is illustrated by the code snippet above: even
if the long variable names explain well what they represent, checking
the correctness of the formula for \( y \) is harder than in the program
that employs the variables v0
, g
, t
, and y0
.
For all variables where there is no associated precise mathematical
description and symbol, one must use descriptive variable names
which explain the purpose of the variable. For example, if a problem
description introduces the symbol \( D \) for a force due to air
resistance, one applies a variable D
also in the program. However,
if the problem description does not define any symbol for this force,
one must apply a descriptive name, such as air_resistance
,
resistance_force
, or drag_force
.
Certain words are reserved in Python because they are used to build up
the Python language. These reserved words cannot
be used as variable names:
and
,
as
,
assert
,
break
,
class
,
continue
,
def
,
del
,
elif
,
else
,
except
,
False
,
finally
,
for
,
from
,
global
,
if
,
import
,
in
,
is
,
lambda
,
None
,
nonlocal
,
not
,
or
,
pass
,
raise
,
return
,
True
,
try
,
with
,
while
, and
yield
.
If you wish to use a reserved word as a variable name, it is common
to an underscore at the end. For example, if you need
a mathematical quantity \( \lambda \) in the program, you may work
with lambda_
as variable name.
See Exercise 16: Find errors in Python statements for examples on legal and illegal
variable names.
Program files can have a freely chosen name, but stay away from names
that coincide with keywords or module names in Python. For instance,
do not use math.py
, time.py
, random.py
, os.py
, sys.py
,
while.py
, for.py
, if.py
, class.py
, or def.py
.
Along with the program statements it is often informative to provide
some comments in a natural human language to explain the idea behind
the statements. Comments in Python start with the #
character, and
everything after this character on a line is ignored when the program
is run. Here is an example of our program with explanatory comments:
# Program for computing the height of a ball in vertical motion.
v0 = 5 # initial velocity
g = 9.81 # acceleration of gravity
t = 0.6 # time
y = v0*t - 0.5*g*t**2 # vertical position
print y
This program and the initial version in the section Using variables
are identical when run on the computer, but for a human the latter is
easier to understand because of the comments.
Good comments together with well-chosen variable names are necessary for any program longer than a few lines, because otherwise the program becomes difficult to understand, both for the programmer and others. It requires some practice to write really instructive comments. Never repeat with words what the program statements already clearly express. Use instead comments to provide important information that is not obvious from the code, for example, what mathematical variable names mean, what variables are used for, a quick overview of a set of forthcoming statements, and general ideas behind the problem solving strategy in the code.
If you use non-English characters in your comments, Python will complain with error messages like
SyntaxError: Non-ASCII character '\xc3' in file ...
but no encoding declared; see
http://www.python.org/peps/pep-0263.html for details
Non-English characters are allowed if you put the following
magic line in the program before such characters are used:
# -*- coding: utf-8 -*-
(Yes, this is a comment, but it is not ignored by Python!)
Instead of just printing the numerical value of y
in our
introductory program, we now want to write a more informative text,
typically something like
At t=0.6 s, the height of the ball is 1.23 m.
where we also have control of the number of digits (here \( y \) is
accurate up to centimeters only).
The output of the type shown above is accomplished by a print
statement combined with some technique for formatting the numbers.
The oldest and most widely used such technique is known as printf
formatting (originating from the function printf
in the C
programming language). For a newcomer to programming, the syntax of
printf formatting may look awkward, but it is quite easy to learn and
very convenient and flexible to work with. The printf syntax is used
in a lot of other programming languages as well.
The sample output above is produced by this statement using printf syntax:
print 'At t=%g s, the height of the ball is %.2f m.' % (t, y)
Let us explain this line in detail. The print
statement prints a
string: everything that is enclosed in quotes (either single: '
, or
double: "
) denotes a string in Python. The string above is formatted
using printf syntax. This means that the string has various
"slots", starting with a percentage sign, here %g
and %.2f
,
where variables in the program can be put in. We have two "slots" in
the present case, and consequently two variables must be put into the
slots. The relevant syntax is to list the variables inside standard
parentheses after the string, separated from the string by a
percentage sign. The first variable, t
, goes into the first
"slot". This "slot" has a format specification %g
, where the
percentage sign marks the slot and the following character, g
, is a
format specification. The g
format instructs
the real number to be written as
compactly as possible. The next variable, y
, goes into the second
"slot". The format specification here is .2f
, which means a real
number written with two digits after the decimal place. The f
in the .2f
format stands for float, a short form for floating-point number,
which is the term used for a real number on a computer.
For completeness we present the whole program, where text and numbers are mixed in the output:
v0 = 5
g = 9.81
t = 0.6
y = v0*t - 0.5*g*t**2
print 'At t=%g s, the height of the ball is %.2f m.' % (t, y)
The program is found in the file ball_print1.py in the src/formulas
folder of the collection of programs
associated with this document.
There are many more ways to specify formats. For example, e
writes a
number in scientific notation, i.e., with a number between 1 and 10
followed by a power of 10, as in \( 1.2432\cdot 10^{-3} \). On a computer
such a number is written in the form 1.2432e-03
. Capital E
in the
exponent is also possible, just replace e
by E
, with the result
1.2432E-03
.
For decimal notation we use the letter f
, as in %f
, and the
output number then appears with digits before and/or after a comma,
e.g., 0.0012432
instead of 1.2432E-03
. With the g
format, the
output will use scientific notation for large or small numbers and
decimal notation otherwise. This format is normally what gives most
compact output of a real number. A lower case g
leads to lower case
e
in scientific notation, while upper case G
implies E
instead
of e
in the exponent.
One can also specify the format as 10.4f
or 14.6E
, meaning in the
first case that a float is written in decimal notation with four
decimals in a field of width equal to 10 characters, and in the second
case a float written in scientific notation with six decimals in a
field of width 14 characters.
Here is a list of some important printf format specifications (the program printf_demo.py exemplifies many of the constructions):
Format | Meaning |
---|---|
%s | a string |
%d | an integer |
%0xd | an integer in a field of with x, padded with leading zeros |
%f | decimal notation with six decimals |
%e | compact scientific notation, e in the exponent |
%E | compact scientific notation, E in the exponent |
%g | compact decimal or scientific notation (with e ) |
%G | compact decimal or scientific notation (with E ) |
%xz | format z right-adjusted in a field of width x |
%-xz | format z left-adjusted in a field of width x |
%.yz | format z with y decimals |
%x.yz | format z with y decimals in a field of width x |
%% | the percentage sign % itself |
For a complete specification of the possible printf-style format strings, follow the link from the item printf-style formatting in the index of the Python Standard Library online documentation.
We may try out some formats by writing more numbers to the screen in our program (the corresponding file is ball_print2.py):
v0 = 5
g = 9.81
t = 0.6
y = v0*t - 0.5*g*t**2
print """
At t=%f s, a ball with
initial velocity v0=%.3E m/s
is located at the height %.2f m.
""" % (t, v0, y)
Observe here that we use a triple-quoted string, recognized by
starting and ending
with three single or double quotes: '''
or
"""
.
Triple-quoted strings are used for text that spans several lines.
In the print
statement above, we print t
in the f
format, which
by default implies six decimals; v0
is written in the .3E
format,
which implies three decimals and the number spans as narrow field as
possible; and y
is written with two decimals in decimal notation in
as narrow field as possible. The output becomes
Terminal> python ball_print2.py
At t=0.600000 s, a ball with
initial velocity v0=5.000E+00 m/s
is located at the height 1.23 m.
You should look at each number in the output
and check the formatting in detail.
Python offers all the functionality of the printf format and much more through a different syntax, often known as format string syntax. Let us illustrate this syntax on the one-line output previously used to show the printf construction. The corresponding format string syntax reads
print 'At t={t:g} s, the height of the ball is {y:.2f} m.'.format(
t=t, y=y)
The "slots" where variables are inserted are now recognized by
curly braces rather than a percentage sign. The name of the variable
is listed with an optional colon and format specifier of the same
kind as was used for the printf format. The various variables and
their values must be listed at the end as shown. This time the
"slots" have names so the sequence of variables is not important.
The multi-line example is written as follows in this alternative format:
print """
At t={t:f} s, a ball with
initial velocity v0={v0:.3E} m/s
is located at the height {y:.2f} m.
""".format(t=t, v0=v0, y=y)
We often want a computer program to write out text that spans several
lines. In the last example we obtained such output by triple-quoted
strings. We could also use ordinary single-quoted strings and a
special character for indicating where line breaks should occur. This
special character reads \n
, i.e., a backslash followed by the letter
n
. The two print
statements
print """y(t) is
the position of
our ball."""
print 'y(t) is\nthe position of\nour ball'
result in identical output:
y(t) is
the position of
our ball.