4. Python Basics#

Last Revised September 26, 2022

4.1. Using Python interactively#

For some tasks, Python can be used interactively, much like a scientific calculator (and later, like a graphing scientific calculator) and that is how we will work for this section.

There are multiple ways of doing this, and I invite you to experiment with them all at some stage:

  • With the “bare” IPython console; this is available in many ways, including from the Anaconda Navigator by opening Qt Console

  • With Spyder, which can be accessed from within the Anaconda Navigator by opening Spyder; within that, there is an interactive Python console frame at bottom-right.

  • In Jupyter notebooks (like this one), which can be accessed from within the Anaconda Navigator by opening JupyterLab.

I suggest learning one tool at a time, starting with this Jupyter notebook; however if you wish to also one of both of the alternatives above, go ahead.

4.2. Running some or all cells in a notebook#

A Jupyter notebook consists of a sequence of cells, and there are two types that we care about:

  • Code cells, which contain Python code

  • Markdown cells (like all the ones so far), which contain text and mathematics, using the Markdown markup notation for text combined with LaTeX markup notation for mathematical formulas.

Running a Code cell executes its Python code; running a Markdown cell formats its content for nicer output.

There are several ways to run a cell:

  • The “Play” (triangle icon) button above

  • Typing “Shift-Return” (or “Shift-Enter”)

Both of these run the current cell and then move down to the next cell as “current”.

Also, the menu “Run” above has various options — hopefully self-explanatory, at least after some experimentation.

To get a Markdown cell back from nicely formatted “display mode” back to “edit mode”, double click in it.

It will be convenient to see the value of an expression by simply making it the last line of a cell.

2 + 2
4

To see several values from a cell, put them on that last line, separated by commas; the results will appear also separated by commas, and in parentheses:

2 + 2, 6 - 1
(4, 5)

(As we will see in the next section, these are tuples; a very convenient way of grouping information.)

4.3. Numbers and basic arithmetic#

Python, like most programming languages distinguishes integers from floating point (“real”) numbers; even “1.0” is different from ‘1’, the decimal point showing that the former is a floating point number.

One difference is that there is a maximum possible floating point number of about \(10^{300}\), whereas Python integers can be arbitrarily large — see below with exponentiation.

Addition and subtraction with “+” and “-” are obvious, as seen above.

2 + 2, 6 - 2
(4, 4)

However, there are a few points to note with multiplication, exponentiation, and division.

4.3.1. Multiplication and exponentiation#

Firstly, the usual multiplication sign not in the standard character setor on standard keyboards, so an asterisk “*” is used instead:

2 * 3
6

Likewise exponentiation needs a special “keyboard-friendly” notation, and it is a dobuble asterisk “**” (not “^”):

2**3
8

Numbers with exponents can be expressed using this exponential notation, but note how Python outputs them:

5.3*10**21
5.3e+21
7*10**-8
7e-08

This “e” notation is the standard way to describe numbers with exponents, and you can input them that way too.

When printing numbers, Python decides if the number is big enough or small enough to be worth printing with an exponent:

2e-10, 3E-5, 3e-4, 5e+4, 10000000000, 6e15, 6e16
(2e-10, 3e-05, 0.0003, 50000.0, 10000000000, 6000000000000000.0, 6e+16)

Aside: note that either “e” or “E” can be used in input of exponents. However in most contexts, Python is case sensitive; we will see an example soon.

4.3.2. Division#

Division is normaly denoted by “/”

6/3
2.0
5/3
1.6666666666666667

but there are a few things to note with integers.

Firstly as you see above, diving two integers always given a floating point number result, not an integer: note the decimal point in “2.0”.

To do integer division, use “//”

6//3
2
5//3
1

and to get the remainder, use “%”

6%3
0
5%3
2

4.3.3. Complex numbers#

Python uses j for the square root of -1 rather than i, and complex numbers are writen as a + bj or just bj for purely imaginary numbers. (Here ‘a’ and ‘b mut be literal numbers, nt mnakem of variables.)

The coeffcient b in the imaginary part is always needed, even if it is 1.

2 + 2j, (2+2j)**2, 1j, 1j**2
((2+2j), 8j, 1j, (-1+0j))

but

j
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [16], in <cell line: 1>()
----> 1 j

NameError: name 'j' is not defined

4.4. Boolean values (True-False)#

These are True and False, capitalized.

Many other options are allowed, like using 0 for False and 1 for True, but for the sake of redability, I discourage that.

The basic logical operations are done wth the usual English words: “and”, “or” and “not”

True and True, True and False, False and False 
(True, False, False)
True or True, True or False, False or False 
(True, True, False)

Both “and” and “or” are use lazy or “short-circuiting” evaluation: if the T/F at left determines the overall truth value answer (it is False with and, True with or) then the term at right is not evaluated.

For example, the following avoids division by zero (the syntax will be explained later, but hopefuly it is mostly clear.)

if q != 0 and -1 < p/q < 1:
    print(f"{p}/{q} is a proper fraction")
else:
    print(f"{p}/{q} is not a proper fraction")

4.5. Comparisons#

Comparisons of numbers and tests for equality exist, with two catches:

So in all:

< <= == != >= >

One convenient difference from most programming languages is that comparisons can be chained, as seen in the example above:

-1 < p/q < 1

is equivalant to

-1 < p/q and p/q < 1

but is both more readable and more efficient, because the middle term is only evaluated once.

Like and and or, this is short-circuiting.

Chaining can even be done in cases where usual mathematical style forbids, with reversing of the direction of the inequalities:

2 < 4 > 3
True

4.6. Character strings#

Chunks of text can be described by surrounding them either with double quotes (“real quotation marks”) or so-called ‘single quotes’, (which are actualy apostrophes).

"I recommend using 'double quote' characters, except perhaps when quote marks must appear within a string, like here."
"I recommend using 'double quote' characters, except perhaps when quote marks must appear within a string, like here."

However, using apostrophes (single right quotes) is also allowed by Python, perhaps because they are slightly easier to type.

4.6.1. String concatenation and duplication#

To concatenate two strings, “add” them with +.

Also, consistent with that, making multiple copies of a string is done by “mutiplication”, with *

greeting = "Hello"
audience = "world"
sentence = greeting + " " + audience + "."
print(sentence)
print(3*(greeting+' '))
Hello world.
Hello Hello Hello 

4.7. Naming quantities, and displaying information with print#

It often helps to give names to quantities, which is done with assignment statements. For example, to solve for \(x\) in the very simple equation \(ax + b = 0\) for given values of \(a\) and \(b\), let us name all three quantities:

a = 3
b = 7
x = -b/a

(Note: this is why testing for equality uses == instead of =.)

Running the above cell just computes the three values with no output. To see the values, a more flexible alternative to the “last line of a cell” method is the function print:

print(a, b, x)
3 7 -2.3333333333333335

That output does not explain things very clearly; we can add explanatory text to the printed results in several ways. Most basically:

print("For a =", a, "and b =", b, "the solution of ax + b = 0 is", x)
For a = 3 and b = 7 the solution of ax + b = 0 is -2.3333333333333335

The above prints six items — three text strings (each quoted), three numbers — with the input items separated by commas.

There is an alternative notation for such output, called “f-strings”, which use braces to specify that the value of a variable be inserted into a string of text to display:

print(f"For a = {a} and b = {b} the solution of ax + b = 0 is {x}")
For a = 3 and b = 7 the solution of ax + b = 0 is -2.3333333333333335

In this example each pair of braces inserts the value of a variable; one can instead put an expression in braces to have it evaluated and that value displayed. So in fact we could skip the variable \(x\) entirely:

print(f"For a = {a} and b = {b} the solution of ax + b = 0 is {-b/a}")
For a = 3 and b = 7 the solution of ax + b = 0 is -2.3333333333333335

We can also display the equation more directly:

print(f"The solution of {a} x + {b} = 0 is {-b/a}")
The solution of 3 x + 7 = 0 is -2.3333333333333335

A final shortcut with print: if an expression in braces ends with =, both the expression and its value are displayed:

print(f"For {a=} and {b=} the solution of ax + b = 0 is {-b/a=}")
For a=3 and b=7 the solution of ax + b = 0 is -b/a=-2.3333333333333335

4.8. Some mathematical functions and constants: module math#

Python includes many modules and packages that add useful defintions of functions, constants and such. For us, the most fundamental is math, which is a standard part of Python.

Aside: we will soon learn about another package numpy and then mostly use that instead of math. I mention math for now because it is a core part of Python whereas numpy is a separate “add-on”, and you should be aware of math if only because many references on doing mathematical stuff with Python will refer to it.

We can access specific items with a fromimport command; to start with, two variables containing famous values:

from math import pi, e
print(f'pi is approximately {pi}')
pi is approximately 3.141592653589793
print(f'e is approximately {e}')
e is approximately 2.718281828459045

Each is accurate to about 16 significant digits; that is the precision of the 64-bit number system standard in most modern computers.

4.8.1. Names (like “e” and “pi”) are case-sensitive#

We can now return to the comment above about case sensitivity. Compare the results of the following two input lines:

print(f'e = {e}')
e = 2.718281828459045
print(f'E = {E}')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [33], in <cell line: 1>()
----> 1 print(f'E = {E}')

NameError: name 'E' is not defined

4.8.2. Some math functions#

Module math also provides a lot of familiar mathematical functions

from math import sin, cos, cosh

which can be used like this:

sin(pi/4)
0.7071067811865475
cos(pi) 
-1.0
cosh(0)
1.0

4.8.2.1. Notes#

  • All Python functions need parentheses around their arguments; no lazy shortcuts with trig. functions and such.

  • Trig. functions use radians, not degrees.

4.8.3. Importing all of a module#

With the command

import math

we get access to many functions such as tan, but need to address them by fully qualified name, like math.tan:

print(f"tan(pi/4) = {math.tan(pi/4)}")
tan(pi/4) = 0.9999999999999999

If we had not already imported pi above, its full name math.pi would also be needed, as in:

print(f"tan(pi/4) = {math.tan(math.pi/4)}")
tan(pi/4) = 0.9999999999999999

Aside: The imperfection of computer arithmetic becomes clear: the exact value is 1 of course. However, the precision of about 16 decimal places is far greater than for any experimental measurement (so far), so this is usually not a problem in practice.

4.8.4. Wild imports: avoid, usually#

There is another way of importing all the contents of a module so that they are available on a “first name basis”, called a wild import; it is like the single-item imports above with from math import ... but no with an asterisk (often called the wild-card character in this context) as the name of the items to import:

from math import *
log(10)
2.302585092994046

Wild imports can be convenient when working interactively (using Python like a scientific calculator) through saving a bit of typing, but I strongly recommend using the previous more specific approaches when creating files and programs.

One reason is that it is then unambiguous where a given item came from, even if multiple import commands are used. For example, we will see later than there are both math.cos and numpy.cos, and they behave differently in some situations.

Another reason for explicit imports is for internal efficiency in storage and execution time; wild imports can potentially load thousands of items from a large module even if only a few are used.

4.9. Logarithmic functions#

We just saw that there is a function log in module math, but which base does it use?

log(10)
2.302585092994046
log(e)
1.0

Evaluating these two expressions reveals that “log()” is the natural logarithm, base \(e\);
what mathematicians usually call “\(\ln\)”.

For the base ten version “\(\log_{10}\)” (sometimes just called “\(\log\)”) use log10:

log10(100)
2.0

4.9.1. Powers and roots#

A square root can of course be computed using the 1/2 power, as with

16**0.5
4.0

but this function is important enough to have a named form provided by module math:

sqrt(2)
1.4142135623730951

4.10. Notes on organization and presentation of course work#

If you are doing the exercises in these notes for a course, record both your input and the resulting output, in a document that you will submit for feedback and then grading, suc as a moified copy of this notebook.

I also encourage you to make notes of other things that you learn, beyond what must be submitted — they will help later in the course.

Also, every document that you submit, hand-written or electronic, should start with:

  • A title,

  • your name (possibly also with your email address), and

  • the date, of the current version.

(See the Title Cell above for example.)