This notebook contains material for CBE 20258 Numerical and Statistical Analysis taught at the University of Notre Dame. (c) Professors Alexander Dowling, Ryan McClarren, and Yamil Colón. This collection of notebooks cbe-xx258 is available on Github.

1.2 Learning Python Basics

Reference: Chapter 1 of Computational Nuclear Engineering and Radiological Science Using Python, R. McClarren (2018)

1.2.1 Learning Objectives

After studying this notebook, completing the activities, and asking questions in class, you should be able to:

1.2.2 Hello World and Interactive Sessions

In almost any computer language the first thing you do is create a program called "Hello world!".

This notebook is an interactive session. We just type the command print("Hello World.") and the press Shift+Enter to execute.

In [1]:
print("Hello World.")
Hello World.
Home Activity: Print the first two lines of your favorite poem or song.

Hint: Use \n to create a new line.

In [ ]:
 

Unicode Characters

In [2]:
print("The temperature was 56 °F this morning.")
The temperature was 56 °F this morning.
Home Activity: Write a print statement using at least two unicode characters.
In [ ]:
 

1.2.2.1 Command Line Mode

Above, we used the interactive mode, which means the result of each line is displayed when I enter the line.

It is more common to put your code into a separate file and then execute it by typing

python codename.py

where codename.py is the name of your file.

How to access a Python interpreter?

  • Mac or Linux: Open terminal and type python
  • Mac, Linux, or Windows: Use an IDE.

Anaconda is the easiest free Python environment to install. It is already available in B19.

Optional Home Activity: Install Anaconda on your computer.

Hint: Start at https://www.anaconda.com/distribution/#download-section. Ask questions in tutorial if you get stuck.

1.2.3 Comments

Comments are your friend. They can be time consuming to add, but never have I looked back at old code and regreted adding them.

A comment is a annotation in your code to

  • inform the reader, often yourself, of what a particular piece of code is trying to do
  • indicate the designed output, result, etc. of a part of the code
  • make the code more readable

Any code you submit for a class assignment must be well commented! This is not to punish you, but to help you.

You use the pound (aka hashtag) to comment out the rest of a line: everything that follows the # is ignored by python. Therefore, you can put little notes to yourself or others about what is going on in the code.

In [3]:
#This next line should compute 9*9 + 19 = 100
print(9*9 + 19)

#You can also make comments inside a line
9*9 #+ 19
100
Out[3]:
81

There are also ways to make multiline comments by use a triple quote '''

In [4]:
'''The beginning of a multiline comment.
This comment will be followed by meaningless 
code.  Enjoy '''
print("I am the very model of a modern major general.")
I am the very model of a modern major general.
Home Activity: Add comments to the following calculation. At the top, write a sentence describing the program in the multiline comment block. Then fill in each empty single line comment with units.
In [5]:
'''

'''

# 
r = 1.0

# 
pi =  3.14159265359

# Calculate sphere area (m^2)
area = 4 * pi * r**2
print("Sphere surface area:",area,"m^2")

#
vol = 4/3 * pi * r**3
print("Sphere volume:",vol,"m^3")
Sphere surface area: 12.56637061436 m^2
Sphere volume: 4.188790204786667 m^3

1.2.4 Errors

We call errors in computer programs bugs. Even experienced programmers write code with bugs. We will learn best practice procedures to try to rid a code of bugs, but even the most sophisticated software quality assurance techniques will not catch every one. Let's look at a good bug and a bad bug.

1.2.4.1 "Good" Bugs

Good bug: A syntax mistake that Python will catch and scream about.

Example

In [6]:
#This is a good bug because the python interpreter complains
9*9 + 
  File "<ipython-input-6-d848fea5e32c>", line 2
    9*9 +
          ^
SyntaxError: invalid syntax
Home Activity: Create another example of a "good" bug. Share with a friend.
In [ ]:
 

1.2.4.2 "Bad" Bugs

Bad bug: A flaw in the logic of the computer program. These are much harder to catch.

Example: We want to compute

$$(3 + 5)^2 = 8^2 = 64$$

But we input:

In [ ]:
3 + 5**2
#You don't get the correct answer, and no one tells you that you're wrong.
Home Activity: Copy the code below and then fix the bad bug.
In [ ]:
(3 + 5)**2

This is an example of the power and feebleness of computers. A computer can do anything you tell it to, but it doesn't necessarily do what you want it to. Always keep this in mind: just because the computer did something, that doesn't mean it did what you wanted.

Later we will talk in more detail about bugs, finding bugs (called debugging), and testing of code.

1.2.5 Indentation

Python is, by design, very picky about how you lay out your code. It requires that code blocks be properly indented. We'll discuss what code blocks are later, but your code needs to be properly aligned to make this work.

In [7]:
#If I improperly indent, my code won't work
print("Not indented")
    print("indented, but it shouldn't be")
  File "<ipython-input-7-d3b8fb0c247c>", line 3
    print("indented, but it shouldn't be")
    ^
IndentationError: unexpected indent

Notice that none of my code executed because of the indentation error. An indent tells the Python interpreter the indented code is part of a code block and needs to be executed in a special way. Only at certain times can one indent and it makes sense. We will revisit this in a few lectures.

Home Activity: Copy the code below and fix the indentation error.
In [ ]:
print("Not indented")
print("indented, but it shouldn't be")

1.2.6 Input

You can prompt the user for input using the input command:

In [ ]:
user_value = input("Enter a number: ")
user_value = float(user_value)
print("2 *", user_value,"=", 2*user_value)
In [ ]:
user_value = input("Enter a number (just type 7): ")
user_value = int(user_value)
if user_value == 7:
    print("Correct, we have a winner")
    print("Claim your prize")
else:
    print("You guessed poorly.")

Notice that in this example we used an if-else statement. The if-else statement is a way to execute different parts of the code based on some conditional expression. This type of execution is sometimes called branching or selection. We will discuss this in detail below.

Also notice the indentation in the if-else block.

Home Activity: Rerun the code above. Find input values that execute each part (a.k.a., branch, section) of the if statement. In other words, find one input value that causes the program to output "Claim your prize". Then find a different input value that causes the program to output "You guessed poorly". Record your answer below in the text (Markdown) cell:

Answer to Home Activity:

Input that printed "claim your prize":

Input that printed "You guessed poorly":

1.2.7 Variables

Information, or data, is stored in variables. Common types of variables include floating point numbers (decimals), integer numbers, and text to name a few. For a complete list of the python data types, see https://docs.python.org/3.4/library/stdtypes.html

1.2.7.1 Integers

Integers are whole numbers, including the negatives. They never have a fractional, or decimal, part and should only be used for data that is a count.

To assign an integer to a variable use the equals sign.

In [ ]:
#assign the value 2 to x
x = 2
print(x*2.0)

#check that x is an integer
type(x)

Integers are useful for things that can be counted: perhaps that number of times we execute a loop, the number of elements of a vector, or the number of students in a class.

Home Activity: Copy the code from above and modify to multiple x by 2 instead of 2.0. What is the variable type now?
In [ ]:
#assign the value 2 to x
x = 2
print(x*2)

#check that x is an integer
type(x)

1.2.7.2 Floating Point Numbers

Floating point numbers are numbers that do have a fractional part. Most numbers in engineering calculations are floating point types.

In [ ]:
#Now make some others floating point variables
y = 4.2
print("y =",y)
print(type(y))
#note that exponentiation is **
z = (x / y)**3
print("(2 / 4.2)**3 =",z)

The way that floating point numbers are represented on a computer has only a finite precision. That means we cannot represent a number exactly in many cases. We'll see later an example of how floating point accuracy can make a difference in a calculation.

Home Activity: Add 1E-10 to 1E-20. Is the answer what you expect?

Hint: 1E-20 is shorthand for $1 \times 10^{-20}$, which is sometimes called scientific notation.

In [ ]:
x = 1E-10 + 1E-20
print(x)

1.2.7.3 Built-in Mathematical Functions

There are almost every common mathematical function you might need for python already built in. To use them you have to import that math functions using the command import. In the code below, I set it up so that to use a math function you use the syntax math.[function] where [function] is the name of the function you want to call.

See https://docs.python.org/3.4/library/math.html for the complete list of built-in mathematical functions.

In [ ]:
import math as m
#take cosine of a number close to pi
theta = 3.14159
trig_variable = m.cos(theta)
print("cos(",theta,") =",trig_variable)

#use the exponential to give me e
e = m.exp(1)
print("The base of the natural logarithm is",e)

#python has a built-in pi as well
print("The value of pi is",m.pi)

Notice how in the print statements, if I give it multiple arguments, it prints each with a space in between. The natural logarithm is just math.log and the base 10 logarithm is math.log10.

In [ ]:
print("The natural log of 10 is",m.log(10))
print("The log base-10 of 10 is",m.log10(10))

There are two non-obvious mathematical operators, integer division: //, and the modulus (or remainder): %

In [ ]:
# 7 / 3 is 2 remainder 1
print("7 divided by 3 is",7//3,"remainder",7%3)
print("851 divided by 13 is",851//13,"remainder",851%13)
Home Activity: Study and execute the code below. Then write a sentence to explain the different between integer and floating point division.
In [ ]:
# integer division
print("7 // 3 = ",7//3)

# floating division
print("7 / 3 = ",7/3)

Write a sentence to explain difference between integer and floating point division:

Let's also look at how to generate a random number.

In [ ]:
import random
print("A random number between 0 and 1: ",random.random())
Home Activity: Generate a random whole number between 0 and 100 using random.random().
In [ ]:
import random
print("A random number between 0 and 100: ",100*random.random())

1.2.8 Strings and Overloading

A string is a data type that is a collection of characters, and needs to be inside quotes:

In [ ]:
#This is a string
aString = "Coffee is for closers."
print(aString)
print("aString")

Anything inside the quotes is taken literally by python. That is why the second print statement above just printed aString.

You can also subset, that is get some of the characters in a string, using brackets. Putting a single number in a bracket gives you the character in that position. Note, python starts numbering at 0 so that 0 is the first character in a string.

In [ ]:
aString[0]
In [ ]:
aString[5]

You can also get a range of characters in a string using the colon. The colon operator is funny in a way in that [a:b] says give me the elements in the string from position a to position b-1.

In [ ]:
aString[1:6]

Python defines its ranges this way so that if the string is of length N, [0:N] returns the whole string.

Negative subsets start at the end of the string (i.e., -1 is the last character of the string).

In [ ]:
aString[-1]
In [ ]:
aString[-5:-2]
Home Activity: Print "closers" by accessing elements of aString
In [ ]:
aString[-8:-1]

With characters (and strings) the + operator is overloaded. What we mean by overloaded, is that it is defined so that the idea of what addition means is conferred to strings. Therefore,

In [ ]:
'Negative Ghostrider: ' + 'the pattern is full'
In [ ]:
'a' + 'b' + 'c'

The + operator concatenates (or smushes together) the strings/characters it operates on.

The multiplication operator is similarly overloaded, though it is not as general. It is simple to think about 'The roof, ' * 3

In [ ]:
'The roof, ' * 3

However, 'The roof, ' * 3.15 is not defined and will give an error:

In [8]:
'The roof, ' * 3.15
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-cf9164a8e59b> in <module>
----> 1 'The roof, ' * 3.15

TypeError: can't multiply sequence by non-int of type 'float'

The upshot is that only an integer times a character/string makes sense. The order of operations is respected

In [ ]:
'The roof, ' * 3 + 'is on fire...'

Minus makes sense, but only sometimes, so it is not allowed.

In [ ]:
'The roof' 
Home Activity: Create the string "row row row your boat gently down the stream" using string multiplication and concatenation.
In [ ]:
"row "*3+"your boat gently down the stream"