Lecture 2
Lecture 2
Introduction
Python
Variables
Formatting Strings
Conditions
Sequences
o Strings
o Lists
o Tuples
o Sets
o Dictionaries
o Loops
Functions
Modules
Object-Oriented Programming
Functional Programming
o Decorators
o Lambda Functions
Exceptions
Introduction
So far, we’ve discussed how to build simple web pages using
HTML and CSS, and how to use Git and GitHub in order to keep
track of changes to our code and collaborate with others.
Today, we’ll dive into Python, one of the two main
programming languages we’ll use throughout this course.
Python
a = 28
b = 1.5
c = "Hello!"
d = True
e = None
Each of these lines is taking the value to the right of the =, and storing it
in the variable name to the left.
int: An integer
float: A decimal number
chr: A single character
str: A string, or sequence of characters
bool: A value that is either True or False
NoneType: A special value (None) indicating the absence of a
value.
Now, we’ll work on writing a more interesting program that can take input
from the user and say hello to that user. To do this, we’ll use another built
in function called input which displays a prompt to the user, and returns
whatever the user provides as input. For example, we can write the
following in a file called name.py:
There are several types of sequences that are similar in some ways, but
different in others. When explaining those differences, we’ll use the
terms mutable/immutable and ordered/unordered. Mutable means
that once a sequence has been defined, we can change individual
elements of that sequence, and ordered means that the order of the
objects matters.
Strings
: Ordered: Yes
Mutable: No
We’ve already looked at strings a little bit, but instead of just
variables, we can think of a string as a sequence of characters. This
means we can access individual elements within the string! For
example:
name = "Harry"
print(name[0])
print(name[1])
prints out the first (or index-0) character in the string, which in this case
happens to be H, and then prints out the second (or index-1) character,
which is a.
Lists
: Ordered: Yes
Mutable: Yes
A Python list allows you to store any variable types. We create a list
using square brackets and commas, as shown below. Similarly to
strings, we can print an entire list, or some individual elements. We
can also add elements to a list using append, and sort a list using sort
# This is a Python comment
names = ["Harry", "Ron", "Hermione"]
# Print the entire list:
print(names)
# Print the second element of the list:
print(names[1])
# Add a new name to the list:
names.append("Draco")
# Sort the list:
names.sort()
# Print the new list:
print(names)
Tuples
: Ordered: Yes
Mutable: No
Tuples are generally used when you need to store just two or three
values together, such as the x and y values for a point. In Python
code, we use parentheses:
point = (12.5, 10.6)
Sets
: Ordered: No
Mutable: N/A
Sets are different from lists and tuples in that they are unordered.
They are also different because while you can have two or more of
the same elements within a list/tuple, a set will only store each
value once. We can define an empty set using the set function. We
can then use add and remove to add and remove elements from that
set, and the len function to find the set’s size. Note that
the len function works on all sequences in python. Also note that
despite adding 4 and 3 to the set twice, each item can only appear
once in a set.
# Create an empty set:
s = set()
: Ordered: No
Mutable: Yes
Python Dictionaries or dicts, will be especially useful in this course. A
dictionary is a set of key-value pairs, where each key has a
corresponding value, just like in a dictionary, each word (the key)
has a corresponding definition (the value). In Python, we use curly
brackets to contain a dictionary, and colons to indicate keys and
values. For example:
# Define a dictionary
houses = {"Harry": "Gryffindor", "Draco": "Slytherin"}
# Print out Harry's house
print(houses["Harry"])
# Adding values to a dictionary:
houses["Hermione"] = "Gryffindor"
# Print out Hermione's House:
print(houses["Hermione"])
""" Output:
Gryffindor
Gryffindor
"""
Loops
""" Output:
0
1
2
3
4
5
"""
""" Output:
0
1
2
3
4
5
"""
This type of loop can work for any sequence! For example, if
we wish to print each name in a list, we could write the code
below:
# Create a list:
names = ["Harry", "Ron", "Hermione"]
""" Output:
H
a
r
r
y
"""
Functions
We’ve already seen a few python functions such as print and input, but
now we’re going to dive into writing our own functions. To get started,
we’ll write a function that takes in a number and squares it:
def square(x):
return x * x
Notice how we use the def keyword to indicate we’re defining a function,
that we’re taking in a single input called x and that we use
the return keyword to indicate what the function’s output should be.
We can then “call” this function just as we’ve called other ones: using
parentheses:
for i in range(10):
print(f"The square of {i} is {square(i)}")
""" Output:
The square of 0 is 0
The square of 1 is 1
The square of 2 is 4
The square of 3 is 9
The square of 4 is 16
The square of 5 is 25
The square of 6 is 36
The square of 7 is 49
The square of 8 is 64
The square of 9 is 81
"""
Modules
As our projects get larger and larger, it will become useful to be able to
write functions in one file and run them in another. In the case above, we
could create create one file called functions.py with the code:
def square(x):
return x * x
And another file called square.py with the code:
for i in range(10):
print(f"The square of {i} is {square(i)}")
However, when we try to run square.py, we run into the following error:
We run into this problem because by default, Python files don’t know
about each other, so we have to explicitly import the square function from
the functions module we just wrote. Now, when square.py looks like this:
for i in range(10):
print(f"The square of {i} is {square(i)}")
Alternatively, we can choose to import the entire functions module and
then use dot notation to access the square function:
import functions
for i in range(10):
print(f"The square of {i} is {functions.square(i)}")
There are many built-in Python modules we can import such
as math or csv that give us access to even more functions. Additionally, we
can download even more Modules to access even more functionality! We’ll
spend a lot of time using the Django Module, which we’ll discuss in the
next lecture.
Object-Oriented Programming
Object Oriented Programming is a programming paradigm, or a way of
thinking about programming, that is centered around objects that can
store information and perform actions.
p = Point(2, 8)
print(p.x)
print(p.y)
""" Output:
2
8
"""
Now, let’s look at a more interesting example where instead of storing just
the coordinates of a Point, we create a class that represents an airline
flight:
class Flight():
# Method to create new flight with given capacity
def __init__(self, capacity):
self.capacity = capacity
self.passengers = []
class Flight():
# Method to create new flight with given capacity
def __init__(self, capacity):
self.capacity = capacity
self.passengers = []
Now, let’s try out the class we’ve created by instantiating some objects:
""" Output:
Added Harry to flight successfully
Added Ron to flight successfully
Added Hermione to flight successfully
No available seats for Ginny
"""
Functional Programming
In addition to supporting Object-Oriented Programming, Python also
supports the Functional Programming Paradigm, in which functions are
treated as values just like any other variable.
Decorators
def announce(f):
def wrapper():
print("About to run the function")
f()
print("Done with the function")
return wrapper
@announce
def hello():
print("Hello, world!")
hello()
""" Output:
About to run the function
Hello, world!
Done with the function
"""
Lambda Functions
square = lambda x: x * x
Where the input is to the left of the : and the output is on the right.
This can be useful when we don’t want to write a whole separate function
for a single, small use. For example, if we want to sort some objects where
it’s not clear at first how to sort them. Imagine we have a list of people,
but with names and houses instead of just names that we wish to sort:
people = [
{"name": "Harry", "house": "Gryffindor"},
{"name": "Cho", "house": "Ravenclaw"},
{"name": "Draco", "house": "Slytherin"}
]
people.sort()
print(people)
This, however, leaves us with the error:
people = [
{"name": "Harry", "house": "Gryffindor"},
{"name": "Cho", "house": "Ravenclaw"},
{"name": "Draco", "house": "Slytherin"}
]
def f(person):
return person["name"]
people.sort(key=f)
print(people)
""" Output:
[{'name': 'Cho', 'house': 'Ravenclaw'}, {'name': 'Draco', 'house': 'Slytherin'}, {'name':
'Harry', 'house': 'Gryffindor'}]
"""
While this does work, we’ve had to write an entire function that we’re only
using once, we can make our code more readable by using a lambda
function:
people = [
{"name": "Harry", "house": "Gryffindor"},
{"name": "Cho", "house": "Ravenclaw"},
{"name": "Draco", "house": "Slytherin"}
]
print(people)
""" Output:
[{'name': 'Cho', 'house': 'Ravenclaw'}, {'name': 'Draco', 'house': 'Slytherin'}, {'name':
'Harry', 'house': 'Gryffindor'}]
"""
Exceptions
During this lecture, we’ve run into a few different exceptions, so now we’ll
look into some new ways of dealing with them.
In the following chunk of code, we’ll take two integers from the user, and
attempt to divide them:
x = int(input("x: "))
y = int(input("y: "))
result = x / y
import sys
x = int(input("x: "))
y = int(input("y: "))
try:
result = x / y
except ZeroDivisionError:
print("Error: Cannot divide by 0.")
# Exit the program
sys.exit(1)
However, we still run into an error when the user enters non-numbers for
x and y:
import sys
try:
x = int(input("x: "))
y = int(input("y: "))
except ValueError:
print("Error: Invalid input")
sys.exit(1)
try:
result = x / y
except ZeroDivisionError:
print("Error: Cannot divide by 0.")
# Exit the program
sys.exit(1)