Comp Lesson 2: Introduction to Python


Good afternoon

Continue our tour of Python:

  1. Calculator and overloading

  2. Basic I/O and exception handling

  3. Packages

The interpreter as a calculator

Mathematical operators include +, -, *, /

[1]:
1 + 1
[1]:
2
[2]:
100 - 50
[2]:
50
[3]:
9 * 9
[3]:
81
[4]:
9 ** 2
[4]:
81
[5]:
21 / 7
[5]:
3.0

/ always returns a float

[6]:
22 / 7
[6]:
3.142857142857143

Use // to truncate and retain only the integer portion:

[7]:
22 // 7
[7]:
3

Or convert the result to an int()

[8]:
int(22/7)
[8]:
3
[9]:
A = 100
A += 1
A
[9]:
101

Discuss immutable aspect of int, and what happens to 100

[10]:
utensils = ["fork", "spoon", "knife"]
utensils
[10]:
['fork', 'spoon', 'knife']
  • is overloaded:

[11]:
utensils += ["chop_sticks"]
utensils
[11]:
['fork', 'spoon', 'knife', 'chop_sticks']

In this context, the right operand must be ‘iterable’:

[12]:
utensils += int(22/7)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [12], in <module>
----> 1 utensils += int(22/7)

TypeError: 'int' object is not iterable

To make this work, to add 5 to the list, wrap it in a list itself:

[13]:
utensils = ["fork", "spoon", "knife"]
utensils += ["chop_sticks"]
utensils += [int(22/7)]
utensils
[13]:
['fork', 'spoon', 'knife', 'chop_sticks', 3]

You could have also used the append function:

[14]:
utensils = ["fork", "spoon", "knife"]
utensils.append("chop_sticks")
utensils
[14]:
['fork', 'spoon', 'knife', 'chop_sticks']

What happens when you add a string directly?

[15]:
utensils = ["fork", "spoon", "knife"]
utensils += "chop_sticks"
utensils
[15]:
['fork',
 'spoon',
 'knife',
 'c',
 'h',
 'o',
 'p',
 '_',
 's',
 't',
 'i',
 'c',
 'k',
 's']

What happens when you append a string wrapped as a list?

[16]:
utensils = ["fork", "spoon", "knife"]
utensils.append(["chop_sticks"])
utensils
[16]:
['fork', 'spoon', 'knife', ['chop_sticks']]

Basic I/O and exception handling

Here, we are going to look at very basic way to get input, and how to anticipate and handle errors.

Let’s try to write a program that will ask the user for words, then prints them out in reverse order

[17]:
print("Please enter a word, followed by Return. When you are done, hit return again")
sentence = []
while True:
    word = input("Your word: ")
    if(word):
        sentence += [word]
    else:
        break

print("-------------------------------")
for i in range( len(sentence)-1, -1, -1):
    print(i, sentence[i])
Please enter a word, followed by Return. When you are done, hit return again
Your word:  apple
Your word:  orange
Your word:  grape
Your word:
-------------------------------
2 grape
1 orange
0 apple

Let’s modify this slightly to ask for series of integers, which our program will sum:

[20]:
print("Please enter an integer, followed by Return. When you are done, hit return again")
nums = []
while True:
    your_int = input("Your integer: ")
    if(your_int):
        nums += [your_int]
    else:
        break

print("-------------------------------")
my_sum = 0
for i in range( len(nums)-1, -1, -1):
    my_sum += nums[i]
    print(i,": ",nums[i])

print("Your total is ", my_sum)

Please enter an integer, followed by Return. When you are done, hit return again
Your integer:  1
Your integer:  2
Your integer:  3
Your integer:  4
Your integer:  5
Your integer:
-------------------------------
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [20], in <module>
     11 my_sum = 0
     12 for i in range( len(nums)-1, -1, -1):
---> 13     my_sum += nums[i]
     14     print(i,": ",nums[i])
     16 print("Your total is ", my_sum)

TypeError: unsupported operand type(s) for +=: 'int' and 'str'
[21]:
print("Please enter an integer, followed by Return. When you are done, hit return again")
nums = []
while True:
    your_int = input("Your integer: ")
    if(your_int):
        nums += [int(your_int)]
    else:
        break

print("-------------------------------")
my_sum = 0
for i in range( len(nums)-1, -1, -1):
    my_sum += nums[i]
    print(i,": ",nums[i])

print("Your total is ", my_sum)
Please enter an integer, followed by Return. When you are done, hit return again
Your integer:  1
Your integer:  2
Your integer:  3
Your integer:  4
Your integer:  5
Your integer:
-------------------------------
4 :  5
3 :  4
2 :  3
1 :  2
0 :  1
Your total is  15
[22]:
print("Please enter an integer, followed by Return. When you are done, hit return again")
nums = []
while True:
    your_int = input("Your integer: ")
    if(your_int):
        nums += [int(your_int)]
    else:
        break

print("-------------------------------")
my_sum = 0
for i in range( len(nums)-1, -1, -1):
    my_sum += nums[i]
    print(i,": ",nums[i])

print("Your total is ", my_sum)
Please enter an integer, followed by Return. When you are done, hit return again
Your integer:  1
Your integer:  2
Your integer:  3
Your integer:  4
Your integer:  computer
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [22], in <module>
      4 your_int = input("Your integer: ")
      5 if(your_int):
----> 6     nums += [int(your_int)]
      7 else:
      8     break

ValueError: invalid literal for int() with base 10: 'computer'

We need is a way to reasonably handle situations like this. We can do so with “exceptions”. Exceptions are objects created at runtime but functions indicating that something is amiss. What is nice about exceptions is that we can engineer code to handle them and behave accordingly. Let’s make our code a bit more robust with a try clause:

[23]:
print("Please enter an integer, followed by Return. When you are done, hit return again")
nums = []
while True:
    your_int = input("Your integer: ")
    if(your_int):
        try:
            nums += [int(your_int)]
        except ValueError as err:
            print(err)
            continue
    else:
        break

print("-------------------------------")
my_sum = 0
for i in range( len(nums)-1, -1, -1):
    my_sum += nums[i]
    print(i,": ",nums[i])

print("Your total is ", my_sum)
Please enter an integer, followed by Return. When you are done, hit return again
Your integer:  1
Your integer:  2
Your integer:  3
Your integer:  4
Your integer:  computer
invalid literal for int() with base 10: 'computer'
Your integer:  5
Your integer:
-------------------------------
4 :  5
3 :  4
2 :  3
1 :  2
0 :  1
Your total is  15

mention the err variable, and how python looks for matching except statements, what happens when no matching except clause is found

Packages

One of the strengths of Python is the set of packages that have functionality beyond the built in core functions and data types. You can install these with anaconda or pip. To access these packages, you need to use the import statement. For example, we covered some basic arithmetic operations earlier. You can get more beefy math with the math module:

[24]:
import math
a = 5 * 4 * 3 * 2 * 1
b = math.factorial(5)
print(a, b)
120 120

To see the functions and data in a package, use the dir()

[25]:
dir(math)
[25]:
['__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'comb',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'dist',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'gcd',
 'hypot',
 'inf',
 'isclose',
 'isfinite',
 'isinf',
 'isnan',
 'isqrt',
 'lcm',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'nan',
 'nextafter',
 'perm',
 'pi',
 'pow',
 'prod',
 'radians',
 'remainder',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'tau',
 'trunc',
 'ulp']

To get help on a function, use the help() function:

[26]:
help(log)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [26], in <module>
----> 1 help(log)

NameError: name 'log' is not defined
[27]:
help(math.log)
Help on built-in function log in module math:

log(...)
    log(x, [base=math.e])
    Return the logarithm of x to the given base.

    If the base not specified, returns the natural logarithm (base e) of x.

A very useful and efficient math module is Numpy. Let’s import it, but take advantage of as to make a shorthand for package contexts:

[28]:
import numpy as np

Let’s also import a commonly used plotting package Matplotlib.

[29]:
import matplotlib.pyplot as plt

The examples below come straight from the NumPy Intro, which I recommend.

Arrays are a fundamental data type in NumPy. Here is how you can create them, convert them to Pandas DataFrames, write them out, and load them:

[30]:
a = np.array([[-2.58289208,  0.43014843, -1.24082018, 1.59572603],
              [ 0.99027828, 1.17150989,  0.94125714, -0.14692469],
              [ 0.76989341,  0.81299683, -0.95068423, 0.11769564],
              [ 0.20484034,  0.34784527,  1.96979195, 0.51992837]])

import pandas as pd

df = pd.DataFrame(a)

print(df)
          0         1         2         3
0 -2.582892  0.430148 -1.240820  1.595726
1  0.990278  1.171510  0.941257 -0.146925
2  0.769893  0.812997 -0.950684  0.117696
3  0.204840  0.347845  1.969792  0.519928
[31]:
df.to_csv('pd.csv')
[32]:
data = pd.read_csv('pd.csv')
data

[32]:
Unnamed: 0 0 1 2 3
0 0 -2.582892 0.430148 -1.240820 1.595726
1 1 0.990278 1.171510 0.941257 -0.146925
2 2 0.769893 0.812997 -0.950684 0.117696
3 3 0.204840 0.347845 1.969792 0.519928

Now let’s plot some data with Matplotlib.

This line ensure the matplotlib figures are sent to this notebook:

[33]:
%matplotlib inline
[34]:
plt.plot(a[:,0], a[:,1])
[34]:
[<matplotlib.lines.Line2D at 0x122865a30>]
../_images/day_03_introduction_to_python_part_2_54_1.png
[35]:
plt.scatter(a[:,0], a[:,1])
[35]:
<matplotlib.collections.PathCollection at 0x122959fd0>
../_images/day_03_introduction_to_python_part_2_55_1.png

We ended at this point in the live lecture. Now let’s go further.

Let’s have some fun with these packages and install a useful data set, the famous iris data

[39]:
import quilt.data.uciml.iris as ir

iris = ir.tables.iris()
[40]:
iris

[40]:
sepal_length sepal_width petal_length petal_width class
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 Iris-virginica
146 6.3 2.5 5.0 1.9 Iris-virginica
147 6.5 3.0 5.2 2.0 Iris-virginica
148 6.2 3.4 5.4 2.3 Iris-virginica
149 5.9 3.0 5.1 1.8 Iris-virginica

150 rows × 5 columns

[41]:
plt.scatter(iris['petal_length'], iris['sepal_length'])
[41]:
<matplotlib.collections.PathCollection at 0x1232b3550>
../_images/day_03_introduction_to_python_part_2_60_1.png
[42]:
#fig, ax = plt.subplots(figsize=(5, 5), layout='constrained')
#ax.scatter('petal_length', 'sepal_length',data = iris)
type(plt)
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
[42]:
[<matplotlib.lines.Line2D at 0x1233023d0>]
../_images/day_03_introduction_to_python_part_2_61_1.png
[43]:
fig = plt.figure()  # an empty figure with no Axes
fig, ax = plt.subplots()  # a figure with a single Axes
fig, axs = plt.subplots(2, 2)  # a figure with a 2x2 grid of Axes
<Figure size 432x288 with 0 Axes>
../_images/day_03_introduction_to_python_part_2_62_1.png
../_images/day_03_introduction_to_python_part_2_62_2.png
[44]:
fig, axs = plt.subplots(1,2)
axs[0].scatter(iris['petal_length'], iris['sepal_length'])
axs[1].scatter(iris['petal_width'], iris['sepal_width'])
[44]:
<matplotlib.collections.PathCollection at 0x123518c10>
../_images/day_03_introduction_to_python_part_2_63_1.png
[45]:
iris.plot()
[45]:
<AxesSubplot:>
../_images/day_03_introduction_to_python_part_2_64_1.png
[47]:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
print(mpl.__version__)
3.5.1
[48]:
iris.plot.box()
[48]:
<AxesSubplot:>
../_images/day_03_introduction_to_python_part_2_66_1.png
[50]:
iris.groupby("class").median()

[50]:
sepal_length sepal_width petal_length petal_width
class
Iris-setosa 5.0 3.4 1.50 0.2
Iris-versicolor 5.9 2.8 4.35 1.3
Iris-virginica 6.5 3.0 5.55 2.0
[52]:
iris.groupby("class").plot.box()
[52]:
class
Iris-setosa        AxesSubplot(0.125,0.125;0.775x0.755)
Iris-versicolor    AxesSubplot(0.125,0.125;0.775x0.755)
Iris-virginica     AxesSubplot(0.125,0.125;0.775x0.755)
dtype: object
../_images/day_03_introduction_to_python_part_2_68_1.png
../_images/day_03_introduction_to_python_part_2_68_2.png
../_images/day_03_introduction_to_python_part_2_68_3.png
[54]:
%load_ext watermark
%watermark -v -p numpy,pandas,matplotlib,quilt,jupyterlab
The watermark extension is already loaded. To reload it, use:
  %reload_ext watermark
Python implementation: CPython
Python version       : 3.9.10
IPython version      : 8.0.1

numpy     : 1.21.5
pandas    : 1.4.0
matplotlib: 3.5.1
quilt     : 2.9.15
jupyterlab: 3.2.8

[ ]: