Comp Lesson 2: Introduction to Python¶
Good afternoon¶
Continue our tour of Python:
Calculator and overloading
Basic I/O and exception handling
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>]
[35]:
plt.scatter(a[:,0], a[:,1])
[35]:
<matplotlib.collections.PathCollection at 0x122959fd0>
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>
[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>]
[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>
[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>
[45]:
iris.plot()
[45]:
<AxesSubplot:>
[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:>
[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
[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
[ ]: