CPSC 2020 Fundamentals of Computational Thinking

About Me

  • Professor Craton
  • Father of two kids - Josiah (3) and Benji (10)
  • Married to Karin
  • We live in Anderson near campus

Academic Career

  • BS in Computer Engineering
  • MA in Higher Education and Student Development
  • MS in Computer Science

Professional Career

  • Software Engineer Team Lead at Genesys
  • Software Consultant

Anything you want to know about me?

Introductions

  • Name
  • Favorite place you went over the break

Syllabus

Link

Quizzes

  • Given regularly at beginning and end of class
  • Allow me to confirm that everyone is keeping up with course material

General Advice

Try New Things

  • College is a time for experimentation and growth
  • Get involved with the community

A ship in port is safe; but that is not what ships are built for. Sail out to sea and do new things.

John Augustus Shedd

Growth Mindset

  • Talents can be developed
  • Learning requires effort
  • Your math skills are not “bad” in a fixed sense
  • Skills have room to grow

Comparison

  • Try not to compare yourself to others
  • Compare yourself to yourself in the past

Never be the brightest person in the room; then you can’t learn anything.

James Watson

Intentional Effort

  • Growth requires effective practice
  • Plan to put in time to learn the topics that matter

The most dangerous way to lose time is not to spend it having fun, but to spend it doing fake work.

Paul Graham

Reading for Tomorrow

S.S. Wilson - Bicycle Technology

Why Computation?

Any sufficiently advanced technology is indistinguishable from magic.

  • Arthur C. Clark
Antikythera mechanism
Antikythera’s harbor Potamos

Antikythera Mechanism

  • Oldest known computer
  • Dated to around 200BCE
  • Found in a shipwreck off the coast of the Greek island Antikythera in 1901
  • Accurately computes positions of astronomical bodies and dates of eclipses
Model
Solar Eclipse

What did you learn about bicycles?

Why did we read about bicycles?

Locomotion Efficiency

To me programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge.

David Sayre

What are computers capable of?

Capabilities

  • Perform mathematical operations
  • Store data
  • Retrieve data

How do computers function

  • Retrieve information from data storage (RAM, drives, network, etc)
  • Perform mathematical operations on data

How does the computer know which operations to perform?

Solving Problems

  • In order to solve complex problems, we need to decompose them to subproblems solvable with simple instructions
  • Computers (or humans) can execute the basic instructions
Chain-of-thought Prompting

Executing Instructions

  • Computer programs are instructions to follow to solve our problem
  • Instructions must be complete and unambiguous
  • It is not easy to craft correct instructions

Instruction Example

Instructing Computers

Telling a Computer What to Do

  • Natural Langugage
  • Applications
  • Programming

Natural Language

  • Comfortable for humans
  • Lacks specificity
  • Lacks precision
  • Difficult for computers to interpret perfectly

Ambiguous Language

The professor said on Monday he would give an exam.

Ambiguous Language

One morning, I shot an elephant in my pajamas. How he got in my pajamas I don’t know.

—Groucho Marx

Large Language Models

  • Completions are inherently stochastic
  • Results may not be exactly correct or what a user intends
  • Need precise inputs to match precise requirements
ChatGPT Math Error
ChatGPT Program Generation

Large Language Models

  • Incredibly powerful tools
  • Growing more powerful rapidly
  • Still require expert knowledge for many use cases

Apps

  • Another approach to instructing computers
  • Work well for pre-defined tasks
  • Must be created by someone

Programming

  • Provides direct instruction to the computer
  • Can be used to compute anything computable
  • This can do nearly anything

Programming

  • Not just for experts
  • Can be a satisfying, creative experience
  • Opens up new means for intellectual expression
  • Is basically a superpower

Programming Challenges

  • Learning a new language
  • Understanding what computers can do efficiently
  • Solving problems algorithmically

Problem Solving

  • Required to program computers
  • Analysis at appropriate level of abstraction

Computational Thinking

Formulating problems such that solutions can be represented as computational steps

Process

  • Problem Formulation - Conceptualize a problem
  • Solution Expression - Formulate unambiguous algorithm
  • Execution - Computer runs instructions to produce result
  • Evaluation - User explores result to confirm thinking

Algorithm

  • Step-by-step process to solve a problem

Example Problems

Simple Computer

  • Tape-based computer with programmable head
  • The number under the head can be scanned
  • One number can be stored in the head
  • A counter in the head can be incremented
Example machine
Alternate representation

Instructions

  • Move head left
  • Move head right
  • Stop if scanned is empty
  • Stop if scanned matches stored
  • Increment counter
  • Increment counter if stored matches scanned
  • Repeat

Count the number of items on the tape

counter should be equal to the count of the items on the tape when the machine stops

Counting

  1. Stop if scanned is empty
  2. Increment counter
  3. Repeat

Search through list for an item matching stored

The machine head should stop with the head on the first match if there is a match or stop after the end of the list if there is no match.

Count the number of matching items in a list

counter should be equal to the count of matching items on the tape when the machine stops

Counting Matches

  1. Increment counter if scanned matches stored
  2. Move head right
  3. Stop if scanned is empty
  4. Repeat

Expressions

Definition

An expression is a syntactic entity in a programming language that may be evaluated to determine its value.

Wikipedia

Syntax

  • Rules that define the combinations of symbols that are considered to be correctly structured
  • There are certain symbols that can be combined in certain ways to produce correct expressions

Evaluation

  • Transformation of expression syntax to the value of the expression
  • Form of computation

Example

1 + 1

Evaluation in Python

  • Expressions in programs are evaluated automatically
  • Single expressions can be quickly evaluated using the Shell
Thonny Shell

Literals

  • Basic components of expressions
  • Evaluation yields on object of a given type

Binary Arithmetic Operators

  • + Addition
  • - Subtraction
  • * Multiplication
  • / Division

Arithmetic Examples

>>> 3.4 + 1.1
4.5
>>> 4 - 3
1
>>> 6 * 3
18
>>> 12 / 4
3.0

Value

  • Result object yielded by an expression
  • Has a type such as integer or string of characters
  • Examples:
    • "Hello, World!" (string)
    • 7 (integer)

Types

  • Set of allowed values for an object
  • Built-in examples include numbers and strings

Numbers

  • Numeric values
2, 3.4, -1, 0

Strings

  • An ordered collection of characters
  • Delineated by single or double quotes
"Hello, world!", "1", ""

Order of Operations

Follows conventions from algebra

  1. Parenthetic subexpressions
  2. Exponentiation
  3. Multiplication and division
  4. Addition and subtraction

Examples

>>> 2 * 3 + 1
7
>>> 1 + 4 / 2
3.0
>>> 2 * (3 + 1)
8

Comparison Operations

  • Always return True or False
Operator Name
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal
== Equal
!= Not equal

Examples

>>> 2 < 3
True
>>> 2 <= 3
True
>>> 2 == 3
False
>>> 2 != 3
True

Logical Operations

  • Always return True or False when operating on True and False values
  • Examples include:
    • not
    • and
    • or

And Truth Table

A B Q
F F F
F T F
T F F
T T T

Or Truth Table

A B Q
F F F
F T T
T F T
T T T

Examples

>>> True and True
True
>>> True and False
False
>>> True or False
True
>>> False or False
False

What is the truth table for the following expression?

not ((not A) and (not B))

Order of Operations

Follows conventions from algebra

  1. Parenthetic subexpressions
  2. Exponentiation
  3. Multiplication and division
  4. Addition and subtraction
  5. Comparison
  6. Logical operations

Official Documentation

Expressions in Python

Variables

Definition

A variable is a named container for a value

Statements

  • A statement is a unit of code that the Python interpreter can execute
  • Example: print("Hello, world")

Assignment Statement

  • Creates or rebinds a variable
  • Gives the variable a value
myvar = 42

Variables

  • A variable is a named container for a value
  • Useful for organizing data flow
  • Provide human-readable names for values
  • Allow values to be reused

Example

>>> base = 5
>>> height = 6
>>> area = (1 / 2) * base * height
>>> area
15.0

Variable Names

  • Should document what the variable is used for
  • May include letters and numbers
  • Should be lowercase
  • May not begin with a number

Reserved Words

Reserved words may not be used as variable names

and     continue  finally  is        raise
as      def       for      lambda    return
assert  del       from     None      True
async   elif      global   nonlocal  try
await   else      if       not       while
break   except    import   or        with
class   False     in       pass      yield

Input Statement

  • input(prompt=None)
  • Accepts user input as an str (string)
  • prompt will be shown to user if provided
  • Documentation for input

input Example

user_msg = input("I'm an AI assistant. How may I help you?")

print("It sounds like you'd like help with the following:")
print(user_msg)
print("As an AI assistant, I'm not able to help with that.")

int

  • int converts strings to integers

Examples

>>> '12'
'12'
>>> int("12")
12
>>> int("Hello world!")
...ValueError...
>>> int("12.0")
...ValueError...

Comments

  • Can be inserted into code as notes for human readers
  • Ignored by Python interpreter
  • Begin with # symbol

Example Program

# Gather user inputs
base = input("Base:")
height = input("Height:")

# Calculate area result
area = (1 / 2) * int(base) * int(height)

# Display result
print("Area of the triange:")
print(area)

Lab Notes

Assignment

  • Used to store values for later use
a = 4
name = input("What is your name")

Converting to Integers

  • int can be used to convert values into integers
>>> "42"
'42'
>>> int("42")
42

type

  • type can be used check the type of a value
>>> type("Hello")
<class 'str'>
>>> type(1)
<class 'int'>

Storing converted values

  • int does not modify value in place
  • Results must be stored or used
answer = "42"
int(answer) # Has no meaningful side effects
answer_num = int(answer) # Stores answer as int

Getting Help

  • Reach out if you need help on a lab
  • Other students can be a great source of help
  • Learn to know when you are using other resources as a crutch

Conditional Execution

Control Flow

  • By default, the Python interpreter runs the next instruction in our program
  • In order to create more complex programs, it is helpful to choose which instruction runs next
  • This is modification of the control plane of program execution

if statement

  • Conditionally runs a block of code
  • A Boolean expression (the condition) follows the if statement
  • The if statement is terminated by a :
if i == 0:

Example

if x > 0:
    print('x is positive')
if control flow diagram

Compound Statements

  • Statements may be grouped together into blocks
  • Blocks of statements should be indented using 4 spaces

Example

if False == True:
    print("This will not print")
    print("This will also not print")

print("This will print")

New Operations

Integer division

  • // performs integer division
  • % is the modulo operator and computes the remainder after division

Division Example

>>> 11 / 4
2.75
>>> 11 // 4
2

Modulo Example

>>> 11 % 4
3
>>> 12 % 4
0
>>> 0 % 4
0
>>> 3 % 2
1

Why would we want a modulo operation?

Even or Odd

number = int(input("Enter a number:"))

if number % 2 == 0:
    print("Your number is even")

if number % 2 == 1:
    print("Your number is odd")

Alternative Execution

Else

  • We may want to run something else when the if check fails
  • This can be accomplished using else

Example

if x % 2 == 0 :
    print('x is even')
else :
    print('x is odd')
else control flow diagram

Example

small_num = input("Enter a number:")
big_num = input("Enter a bigger number:")

if small_num < big_num:
    print("You entered the numbers correctly")
else:
    print("Your second number is too small")

Chained Conditionals

  • We may want more than two branches of execution
  • We can chain multiple conditionals to achieve this

Chained Conditionals

if x < y:
    print('x is less than y')
elif x > y:
    print('x is greater than y')
else:
    print('x and y are equal')
elif control flow diagram

Improved printing

  • The print function will accept multiple items to print
  • Items must be separated by commas

Printing a name

name = input("What is your name?")
print("Hello", name)

Basic string operations

  • Concatenation can be performed using the + operator
  • Duplication can be performed using the * operator
  • Comparison can be performed using standard comparison operators

Example

word1 = input("Enter a word:")
word2 = input("Enter another word:")

if word1 < word2:
    print(word1, "comes before", word2, "alphabetically")
elif word1 > word2:
    print(word1, "comes after", word2, "alphabetically")
else:
    print(word1, "and", word2, "are the same word")

Nested Conditional Execution

Review

  • if conditionally executes code
  • elif conditionally executes alternative code
  • else executes if no other conditions are met

Nesting Conditionals

  • We can nest blocks of code
  • Conditional execution can be nested to create more complex control flow

Example

if x == y:
    print('x and y are equal')
else:
    if x < y:
        print('x is less than y')
    else:
        print('x is greater than y')
Nested Control Flow Diagram

Disney Princess Quiz

How would we approach building a quiz like this?

Process

  • Problem Formulation - Conceptualize a problem
  • Solution Expression - Formulate unambiguous algorithm
  • Execution - Computer runs instructions to produce result
  • Evaluation - User explores result to confirm thinking

Star Wars Quiz

age = int(input("How old are you?"))
color = input("What is your favorite color?")

if age < 25:
    if color == 'red':
        print("You are Darth Maul")
    else:
        print("You are Obi-wan Kenobi")
else:
    if color == 'red':
        print("You are Darth Vader")
    else:
        print("You are Luke Skywalker")

Style

  • Deep nesting can become difficult to read
  • As a rule of thumb, we’d like to avoid nesting more than 3 layers deep
  • Lines should not exceed 79 characters (PEP8)

Exit

  • exit can be used to immediately terminate a program.

Exit Example

dividend = int(input("Enter value for divdend:"))
divisor = int(input("Enter value for divisor:"))

if divisor == 0:
    print("Can't divide by zero")
    exit()

quotient = dividend // divisor
remainder = dividend % divisor

print("Quotient:", quotient)
print("Remainder:", remainder)

Key Topics to Date

  • input and print statements
  • Arithmetic expressions (2 + 3)
  • Comparison operators (2 <= 3)
  • Assignment statements (a=3)
  • Conditional execution (if, elif, else)

Lab Questions

Pokemon Nesting Example

Exceptions

Failure

  • Code can fail for a variety of reasons
  • Some errors can be caught before the program is run
  • Others must be handled during runtime

Example

>>> speed = input("What is the air velocity of an unladen swallow?")
What is the air velocity of an unladen swallow?
What do you mean, an African or a European swallow?
>>> int(speed)
ValueError: invalid literal for int() with base 10:

Exceptions

  • Raised when error occurs during runtime
  • Immediately ends the program with an error message*

Example

num = input("Enter a number between 1 and 10")

square = int(num) * int(num)

print("The square of your number is:", square)

Catching Exceptions

  • It is possible to continue execution after an exception is raised
  • This requires us to catch the exception from a try block

Example

try:
    int("red")
except ValueError:
    print("Please enter a valid number")

Processing Exceptions

  • Report the error to the user
  • Try again
  • Do something else

Try again

entry = input("Enter a number between 1 and 10")

try:
    num = int(entry)
except ValueError:
    entry = input("That's not a number. Try again:")
    num = int(entry)

square = num * num
print("The square of your number is:", square)

Do something else

entry = input("Enter a number between 1 and 10")

try:
    num = int(entry)
except ValueError:
    print("That's not a number. Let's just use 5.")
    num = 5

square = num * num
print("The square of your number is:", square)

Catching all exceptions

  • By default, all exceptions are caught by except
  • This can cause problems
  • You generally want to avoid catching all exceptions

Example

dividend = input("Enter dividend:")
divisor = input("Enter divisor:")

try:
    print("The quotient is", int(dividend) / int(divisor))
except:
    print("You did not enter numbers.")

Ignoring Exceptions

  • We should almost never ignore exceptions
  • It is possible to ignore them using pass

Pass

entry = input("Enter a number between 1 and 10")

try:
    num = int(entry)
except ValueError:
    pass

square = num * num
print("The square of your number is:", square)

Pass keyword

  • The pass keyword is valid in many places
  • It is not explicitly related to exceptions
  • It simply indicates that while a statement is expected, we don’t have anything to do

Example

i = 1

if i == 2:
    pass
else:
    print("i is not 2")

Functions

A function is a named sequence of statements that performs a computation

Calling Functions

  • We’ve already done this
  • Use the function name followed by parens containing arguments to pass

Example

  • int is a function
  • It takes one argument and returns a value
num = int("42")

Return value

  • The name for the value returned from a function

Built-in function

  • Python includes many functions that we may have use for

Input

  • Displays an optional prompt and returns user input
name = input("Enter your name: ")

min and max

  • min and max return the minimum and maximum of their arguments
>>> min(1, 3)
1
>>> max(12, 4)
12

Iterables

  • min and max can also operate on iterables such as strings
>>> min("abc")
'a'
>>> max("green")
'r'

len

  • len can be used to return the length of a value
>>> len("Hello")
5
>>> len("Blue")
4
>>> len("")
0

Type conversions

  • int, float, and str can be used to convert types
>>> int("1")
1
>>> float("1.5")
1.5
>>> str(1.5)
'1.5'

Modules

math

  • The math module can be used to access various math functions
  • import math can be used to create the math object used to access the module
  • A module is a file containing Python definitions and statements

Dot notation

  • Modules contain functions and variables
  • These can be accessed using the . character
import math

print(math.pi)

Example

import math

dist = input("Distance to building: ")
height = input("Building height: ")

angle_rad = math.atan(float(height) / float(dist))
angle_deg = angle_rad * 180 / math.pi

print("Angle to top:", angle_deg)

help

  • help can be used to provide information about an object
  • help(math) provides information about available math functions

random

  • The random module provides access to pseudorandom numbers
  • These numbers will appear random, but are generated deterministically
  • They should not be used in cryptography

Example

import random

# Print random number between 0.0 and 1.0
print(random.random())

randint

  • randint returns a random integer between bounds
# Returns a number between 1 and 10 inclusive
random.randint(1, 10)

choice

  • choice selects one item from an iterable
# Pick a, b, or c
random.choice("abc")

Creating Functions

Function definition

  • Specifies the name of a new function
  • Specifies the sequence of statements that execute when the function is called
  • The function can be reused throughout the program

Flow of Execution

  • Programs generally run from top to bottom
  • Function definitions are not executed
  • Functions run only when called

Example

def print_twice(value):
    print(value)
    print(value)

print_twice("Hello there")

Void functions

  • Void functions do not return a value
  • They may still do useful work
  • print is an example of a void function

Fruitful functions

  • Fruitful functions return a value
  • This value can be used later in your programs
  • input is an example of a fruitful function

Example

def square(n):
    return n*n

print(square(2))
print(square(7))

Parameters and arguments

  • Arguments are the values passed to a functions
  • Parameters are the variable names used inside the function

Return

  • Return allows us to terminate a function and return control to the caller
  • If used with a value, the function returns the value

We can reimplement min ourselves

def min(a, b):
    if a < b:
        return a
    else:
        return b

Functions may call other functions

Example

def square(n):
    return n*n

def cube(n):
    return n * square(n)

print(cube(2))

Recursive functions

  • Functions may call themselves
  • This must be done carefully to avoid infinite recursion
def repeat(task, num_times):
    if num_times > 0:
        task()
        repeat(task, num_times - 1)

def greet():
    print("Hello!")

repeat(greet, 3)
def fib(n):
    if n <= 1:
        return n
    return fib(n-2) + fib(n - 1)

print(fib(20))

Important Dates

Exam 1

  • February 23th
  • In-class Canvas exam
  • May use a single-page, hand-written note sheet

Testing

How do we know if software works?

Software testing is the act of checking whether software satisfies expectations.

Testing

  • Determines correctness in some scenarios
  • Will not find all bugs
def square(n):
    return n*n

How do we know if this code works?

Test Cases

  • We can confirm known outputs
  • assert is a simple tool for this
  • assert will raise an exception if its input expression if false

assert

assert(1==1) # Confirms that 1 is 1
assert(1==2) # Raises AssertionError

Square with Tests

def square(n):
    return n*n

assert(square(0) == 0)
assert(square(1) == 1)
assert(square(2) == 4)
assert(square(25) == 625)

Types of Tests

  • Unit - Tests individual parts of the system
  • Integration - Tests components integrated from smaller components
  • End-to-end - Tests an entire system
Testing Pyramid

Lab Feedback

Managing State

Testability

  • In order to test code, it helps for it to be written with tests in mind
  • Isolation of functionality is important

Readability

  • Code that is easier to test is often easy to read
  • Breaking code at distinct test boundaries can simplify the architecture

Pure Functions

  • No side effects
  • No reliance on external state
  • Always return the same output given the same inputs

Pure Function

def absolute_value(x):
    if x < 0:
        return -x
    else:
        return x

Impure Function

n = 2

def square():
  return n*n

n = 4
print(square())

Global State

  • Global state exists for the life a program
  • Local state exists in a section of code
  • Code that references global state can be more difficult to reason about

Local Variables

  • Are only defined within a function
  • Torn down when function terminates
  • Useful for storing temporary data

Local Variable

def is_freezing(temp, unit):
    if unit == 'C':
        temp_f = temp * 9/5 + 32
    else:
        temp_f = temp

    if temp_f < 32:
        return True
    else:
        return False

Global Variable

  • Defined over the entire scope
  • Torn down only on program termination
  • Useful for storing global data

Global Variable

def get_tip(price):
    return int(percentage) / 100 * float(price)

percentage = input("Tip percentage: ")
price = input("Meal price: ")

print("Tip:", get_tip(price))

How would we test get_tip?

State

  • Managing state is critical for creating readable code
  • Testability is enhance when we limit external state

Modular Design

Modular design emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.

Separation of concerns is a design principle for separating a computer program into distinct sections.

Separation of Concerns

The separation of concerns, which, even if not perfectly possible, is yet the only available technique for effective ordering of one’s thoughts, that I know of.

Edsger Dijkstra

Boundaries

Architectural boundaries should be separated so that changing one part of the system has no effect on any other part of the system.

Bob Martin

Examples

Bank Application

Rock Paper Scissors

  • Get user input
  • Select a computer input
  • Determine a winner
  • Display the results

Exam Review

Key Topics

  • Computational Thinking
  • Expressions and Variables
  • Conditional Execution
  • Functions
  • Testing

Computational Thinking

  • Breaking problems down into computational steps

Expressions and Variables

  • Expressions can be evaluated to produce a value
  • Variables are named containers for values

Conditional Execution

  • if can be used to conditionally execute a section of code
  • elif and else can provide alternatives

Functions

  • Functions provide named sets of instructions that can be called
  • Many built-in functions exist (input, min, etc)
  • Custom functions can be created using def

Testing

  • Software testing is the act of checking whether software satisfies expectations
  • Testable code is often more modular and easier to reason about

Midterm Survey

Iteration

Assignment

  • Variables can be assigned values
x = 1
y = 1 + 2

Updating Variables

  • Sometimes we want to update the values in variables
  • We can set variables to expressions that include those variables
x = x + 1

Increment and Decrement

  • Increment is increase by 1
  • Decrement is decrease by 1
x = x + 1 # Increment
x = x - 1 # Decrement

Augmented Assignment

We can shorten common reassignment using augmented assignment:

x += 1 # Increment
x -= 1 # Decrement

Recursion

  • Functions can be use to create repetition in our programs

Example

def count_to_10_from(n):
    if n > 10:
        return

    print(n)
    count_to_10_from(n + 1)

count_to_10_from(0)

while

  • Repetition in programs is a common task
  • We introduce while to perform operations multiple times

Example

while True:
    answer = input("What is the capital of France?")

    if answer == "Paris":
        print("That's correct!")
        exit()
    else:
        print("Not quite. Try again.")

Indefinite iteration

  • We do not specify how many times a while loop will execute in advance
  • This makes iteration indefinite

Controlling Iteration

  • while accepts a conditional that will stop iteration when false
  • This can be used to control how many times we iterate

Counting

i = 0

while i <= 10:
    print(i)
    i += 1

Infinite Loop

  • We must be careful to avoid looping forever
  • A loop that never stops is called an infinite loop
  • This is a common type of bug

Infinite Loop

i = 0

while True:
    print(i)

break

  • break can be used to terminate iteration
  • Control moves to after the loop body

Example

i = 0

while True:
    if i > 10:
        break
    print(i)
    i = i + 1

continue

  • continue can be reused to skip the remainder of an iteration
  • Control will return to the conditional on the while statement

Example

while True:
    num = input("Enter a number:")

    try:
        square = int(num) ** 2
    except ValueError:
        print("Invalid number")
        continue

    print(square)

Exercise

Stuck in a time loop

Use the following to get problem input:

import sys

count_to = int(sys.stdin.read())

Definite Iteration

Definite Iteration

  • We frequently want to iterate a fixed number of times
  • We may want to iterate over a fixed number of items
  • Definite iteration provides a tool for this

for

  • The for keyword provides definite iteration
  • It will iterate over all items in the supplied iterable

Solution

word = "hello"

for letter in word:
    print(letter)

Count letters in a word

Solution

word = "hello"
count = 0

for letter in word:
    count += 1

print(count)

Sum of digits in a number

Solution

num = input("Enter a number:")

total = 0

for digit in num:
    total = total + int(digit)

print("The digits sum to", total)

Word counter

Solution

text = input("Enter text to count words:")

words = 1

for character in text:
    if character == " ":
        words = words + 1

print(words)

break and continue

  • break and continue can be used with for as expected

Lists

  • A list is a sequence of values
  • Lists are defined using square brackets ([ and ])
  • Lists can be iterated using for

List example

mylist = [1, 2, 3]

for i in mylist:
    print(i)

Lists

  • Lists are covered in much more detail in chapter 8

range

  • range is a function that returns value for use in iteration
  • It can provide a quick way to create a definite loop when combined with for

range example

for i in range(10):
    print(i)

range parameters

  • start - Where to start counting from
  • stop - When to stop counting (exclusive)
  • step - Number to count by (1 by default)

range parameter example

# Count to 30 by 3
for i in range(0, 31, 3):
    print(i)

else

  • for supports an else clause
  • It will be executed if the loop is not interrupted

else example

user_color = input("Enter a color:")

for color in ['red', 'green', 'blue']:
    if user_color == color:
        break
else:
    print("You didn't enter an allowed color")
    exit()

print("You entered a correct color")

Loop Patterns

Construction

  • Initialize variable before the loop starts
  • Perform computation on each loop item
  • Examine variable after the loop completes

Counting

Solution

count = 0

for i in [1, 3, 6, 10, 15, 21]:
    count = count + 1

print(count)

Sum

Solution

total = 0

for num in [1, 3, 6, 10, 15, 21]:
    total = total + num

print(total)

Counting and Summing

  • Helpful pattern to understand
  • Can be easily replaced by len and sum in simple cases

Mean

Solution

total = 0
count = 0

for num in [1, 3, 6, 10, 15, 21]:
    total = total + num
    count = count + 1

mean = total / count

print("Total:", total, "Count:", count, "Mean:", mean)

Could we compute the mean without using a loop?

Solution

nums = [1, 3, 6, 10, 15, 21]

mean = sum(nums) / len(nums)

print("Mean:", mean)

Word Count

How can we count the words in a string?

State diagram

Maximum and Minimum

  • Sometimes we want to compare one value to others
  • Examples include finding a max or a min

Max

Solution

import math

nums = [1, 4, 7, 12, 3]
largest = -math.inf

for num in nums:
    if num > largest:
        largest = num

print(largest)

Min

Solution

import math

nums = [1, 4, 7, 12, 3]
smallest = math.inf

for num in nums:
    if num < smallest:
        smallest = num

print(smallest)

min function

Solution

import math

def min(nums):
    smallest = math.inf

    for num in nums:
        if num < smallest:
            smallest = num

    return num

Check if a word has no vowels

Solution

word = input("Enter a word with no vowels:")
valid_word = True

for letter in word:
    for vowel in 'aeiou':
        if letter == vowel:
            valid_word = False

if valid_word:
    print("That's correct")
else:
    print("Your word included a vowel.")

Strings

Definition

  • A string is a sequence of characters
  • String literals can be created using single or double quotes

Valid Strings

"Hello, world"
'Hello, world'
""
''
"a"
'b'

Accessing Items

  • A string is a sequence
  • Items in the sequence can be accessed using square brackets []

Example

>>> name = "Jordan"
>>> name[0]
'J'
>>> name[2]
'r'
Indexing starts from 0

Immutability

  • Strings in Python are immutable
  • This means they cannot be changed

Example

>>> word = "cat"
>>> word[0]
'c'
>>> word[0] = "b"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

Creating a New String

  • If we need to change a string we must create a new modified version
  • This can be accomplished using string expressions
>>> word = "cat"
>>> word = "b" + word[1] + word[2]
>>> word
'bat'

Looping

  • Strings are iterable
  • We can easily loop over the characters in a string using for

Example

dna = "GGTGTACGGC"

guanine_count = 0

for base in dna:
    if base == 'G':
        guanine_count += 1

print("Guanine bases:", guanine_count)

in

  • The in operator can be used with strings
  • An in expression will return true if the value on the left is contained within the value on the right

Example

>>> "a" in "cat"
True
>>> "b" in "cat"
False
>>> "bat" in "batman"
True
>>> "ant" in "batman"
False

String comparison

  • Comparison operators are defined for strings
  • == checks for equality as expected
  • < and > are a little more complicated

Example

>>> "cat" == "cat"
True
>>> "cat" == "bat"
False
>>> "bat" == "batman"
False

Alphabetical order

  • Generally, comparison operators can be used to confirm whether strings are in alphabetical order
  • All uppercase letters come before all lowercase letter

Example

>>> "bat" < "cat"
True
>>> "cat" > "bat"
True
>>> "bat" < "Cat"
False
>>> "1" < "2"
True
>>> "12" < "102"
False

Create a program to print every other letter in a string

Create a program to find a word in a string and print the position of the word

Solution

sentence = "the quick brown fox jumped over the lazy dog"
word = "fox"

for sent_idx in range(0, len(sentence)):
    for word_idx in range(len(word)):
        if sentence[sent_idx + word_idx] != word[word_idx]:
            break
    else:
        print(sent_idx)

String Methods

Methods

  • Methods are functions that operate on a known piece of data
  • Most operators are shortcuts to object methods

Example

>>> 1 + 2
3
>>> (1).__add__(2)
3

dir

  • dir can be used to list methods available on an object

Example

>>> dir(1)
['__abs__', '__add__', ...]
>>> dir("")
['__add__', ...]

upper and lower

  • upper can be used to uppercase a string
  • lower can be used to lowercase it

Example

>>> a = "Hello, world!"
>>> a.lower()
'hello, world!'
>>> a.upper()
'HELLO, WORLD!'

How could we compare strings ignoring case?

Solution

color = input("Enter a color:")

if color.lower() == "red":
    print("Roses are red")
elif color.lower() == "blue":
    print("Violets are blue")
else:
    print("Unknown color")

find

  • find can be used to get the position of a substring
  • Returns the index of the start of the substring
  • Returns -1 if substring is not found

Example

>>> a = "Hello, world!"
>>> a.find("world")
7

strip

  • strip returns a copy of the string with leading and trailing whitespace removed

Example

>>> text = "    Hello, world!          "
>>> text.strip()
'Hello, world'

startswith

  • startswith will return True if the string begins with the supplied prefix

Example

>>> text = "Hello, world!"
>>> text.startswith("Hello")
True
>>> text.startswith("world")
False

count

  • count will count the number of non-overlapping substrings in some text

Example

>>> sentence = "The quick brown fox jumped over the lazy dog"
>>> sentence.count("o")
4

Slicing

  • String indexing in Python supports returning substrings as well as individual characters
  • A colon (:) is used to separate the start and end index

Example

>>> alphabet = "abcdefghijklmnopqrstuvwxyz"
>>> alphabet[2:4]
'cd'
>>> alphabet[0:5]
'abcde'
>>> alphabet[2:2]
''
>>> alphabet[2:3]
'c'

Negative Indexes

  • In Python, it is legal for an index to be negative
  • A negative index will index from the end of the object

Example

>>> text = "Hello, world!"
>>> text[-1]
'!'
>>> text[-2]
'd'

Inferred indices

  • If a start index is left out, it is assumed to be the start
  • If an end index is left out, it is assumed to be the end

Example

>>> text = "Hello, world"
>>> text[2:]
'llo, world!'
>>> text[:-2]
'Hello, worl'

Formatted String Literals

format

  • Prior editions of the textbook used the format method on strings
  • It is antiquated and has largely been superseded by f-strings since Python 3.6.
  • You will not be required to use or understand the format method in this class

f-strings

  • Provide simple string formatting
  • Python expressions can be included within strings
  • An f should be used before the opening quote of the string literal

Example

>>> f"The answer is {7*6}"

Example

name = input("What is you name?")

print(f"Hello, {name}")

Format Specifiers

  • Can be added after an expression to adjust formatting
  • This can be used for rounding or other purposes such as alignment

Example

num = 1

for pokemon in ["Charmander", "Charmeleon", "Charizard"]:
    print(f"{pokemon:12} {num}")
    num += 1

Example

import random

for _ in range(10):
    print(f"{random.random():.2f}")

Create a program that will capitalize the first word in a provided sentence.

Solution

sentence = "hello world"

sentence = sentence[0].upper() + sentence[1:]

print(sentence)

Create a program that will search a string for a word and display the word along with the 5 characters before and 5 characters after it.

Solution

sentence = "the quick brown fox jumped over the lazy dog"
word = "fox"

index = sentence.find(word)

print(sentence[index - 5: index + len(word) + 5])

Files

Basic Computer Architecture

Storage

  • Instructions are executed by the CPU
  • Values and variables as discussed so far live in main memory

Persistence

  • Main memory is cleared when unpowered
  • Long-term storage must use secondary memory
DRAM
Laptop HDD
SATA SSD
mSATA SSD
NVMe SSD

Files

  • Files are the abstraction used for long-term storage
  • Files are typically organized in a hierarchy
  • Files typically have human-readable names

Opening Files

  • The open function may be used to open a file
  • It requires a filename as a parameter
  • It returns a file handle
File Handle

Read Example

file_handle = open("myfile.txt")

contents = file_handle.read()

print(contents)

Closing Files

  • When we are finished with a file, we should close it to free resources in our programs

Close Example

file_handle = open("myfile.txt")

contents = file_handle.read()

file_handle.close()

print(contents)

Reading Closed File

file_handle = open("myfile.txt")

file_handle.close()

contents = file_handle.read() # Raises Exception

Lines

  • Plain text may be separated into lines for easier consumption
  • Lines are separated by a special character called a newline
  • We can create a newline character in Python using a \n escape sequence

Example

print("Line 1\nLine 2")

Reading Lines

  • It may be helpful to read a file one line at a time
  • Paragraphs may be represented this way in documents
  • Data formats may use lines to separate records

Reading Lines

  • The readline method will return the next line as a string value
  • The readlines method will return an iterable of all lines
  • The file handle can be iterated directly to operate on lines

Example

handle = open("example.py")

first_line = handle.readline()

print(first_line)

Example

handle = open("example.py")

for line in handle:
    print(line, end='')

Exercise

  1. Create a plain text file with numbers on each line
  2. Create a Python program that prints the sum of the numbers in the file

Solution

handle = open("myfile.txt")

total = 0
for line in handle:
    total += int(line)

print(total)

Key Ideas

  • Main memory is volatile and files provide non-volatile storage
  • We can use the open function to get a file handle
  • We can use read to load a string from a file

File Exceptions

Errors in Programs

  • Sources of errors in programs are numerous
  • One common source of errors are incorrect assumptions about the environment in which the program is running

Missing Files

  • An attempt to open a file for reading that does not exist will raise an exception

Example

handle = open("missing.txt")

Handling Exceptions

  • We can use try and except to handle these errors

Example

try:
    handle = open("missing.txt")
except FileNotFoundError:
    print("File not found")

User Selected Files

  • File name need not be hard-coded
  • Names can be entered by a user
  • This makes proper error handling more important

Example

filename = input("Select a file to read:")

try:
    handle = open(filename)
except FileNotFoundError:
    print(f"Error opening {filename}")
    exit(1)

contents = handle.read()

print(contents)

Handling Multiple Exceptions

  • File reading may fail due to missing files
  • File reading may fail due to invalid access rights
  • These can be handled using separate except blocks

Example

filename = input("Select a file to read:")

try:
    handle = open(filename)
except FileNotFoundError:
    print(f"File '{filename}' does not exist")
    exit(1)
except PermissionError:
    print(f"File '{filename}' is not readable")
    exit(1)

contents = handle.read()

print(contents)

Exercise

  • print all capitalized words in a user-selected file.
  • Show an appropriate error message if the file is not found.

Solution

filename = input("Filename:")

try:
    handle = open(filename)
except FileNotFoundError:
    print("File not found")
    exit(1)

contents = handle.read()

for word in contents.split():
    if word.istitle():
        print(word)

Exercise

Count all if, elif, and else keywords in a program

Solution

filename = input("Filename:")

try:
    handle = open(filename)
except FileNotFoundError:
    print("File not found")
    exit(1)

contents = handle.read()

count_if = 0
count_elif = 0
count_else = 0

for word in contents.split():
    if word == "if":
        count_if += 1
    elif word == "elif":
        count_elif += 1
    elif word == "else":
        count_else += 1

print(f"if: {count_if}")
print(f"elif: {count_elif}")
print(f"else: {count_else}")

Key Ideas

  • Reading files creates new surface for errors
  • try and except can be used to deal with exceptions
  • Filenames can be entered by users or come from other dynamic sources

File Writing

File Handles

  • Provide an interface to work with an open file
  • Common operations include reading, writing, and closing

Reading

  • Open a file with default file mode (read)
  • Use the read method to move text content from the file to a string

Example

pyfile = open("example.py")

source = pyfile.read()

print(source)

Writing

  • Open a file with mode set to “w”
  • Use the write method to write to the file

Example

outfile = open("myfile.txt", "w")

outfile.write("Hello, world")

outfile.close()

Closing

  • Files must be properly closed to ensure all data is correctly written

Example

outfile = open("myfile.txt", "w")

outfile.write("Hello, world")

Truncation

  • When a file is opened for writing, it is truncated by default
  • This means all existing content will be destroyed

Appending

  • Files can be opened for appending using the “a” flag

Example

outfile = open("myfile.txt", "a")

outfile.write("Hello, world")

outfile.close()

Exceptions

  • An exception crashing the program can prevent a proper close

Example

outfile = open("myfile.txt", "a")

outfile.write("Hello, world")

int("not a number")

outfile.close()

Closing Files

  • It is important to close files when we finish using them
  • It can be easy to forget to do this
  • with can be used to automatically close a file

Example

with open("myfile.txt", "w") as outfile:
    outfile.write("Hello, world")

with

  • The with statement can be used with all context manager types
  • File handles are one use, but there are many others
  • with always closes the file, even when exceptions are raised

Exercise

Write the first 1000 positive integers to a file

Exercise

Read the values from that file one at a time and write their squares to a second file

Solution

with open("nums.txt") as nums:
    with open("squares.txt", "w") as squares:
        for num in nums:
            square = int(num) * int(num)
            squares.write(f"{square}\n")

Key Ideas

  • Files can be opened with the “w” flag
  • We can avoid truncation with the “a” flag
  • The with statement can be used to automatically close files

Lists

list

  • A list object is a sequence of values
  • Values may be of any type
  • Values may have different types

Creating a list

  • Lists can be created using square brackets enclosing expressions separated by commas
  • [1, 2, 3]
  • ["a", "b", "c"]

Example

mylist = [1, 2, 3]

Empty lists

  • An empty list is a valid data structure
  • This is created using square brackets with nothing inside: []
  • Empty lists evaluate to False in Boolean expressions

Example

if []:
    print("This won't print")

Falsy Values

  • Most Python values evaluate as True in a Boolean expression
  • Exceptions include empty containers and 0-valued numerics
  • More info

Mutability

  • Unlike strings, lists are mutable
  • We can change an item inside a list

Example

mylist = [1, 2, 3]

mylist[0] = 7

print(mylist)

Mapping

  • One way to reason about a list is as a mapping from numbers to elements
  • Language of one value “mapping to” another is also useful in later data structures

Indices

  • Any integer may be an index
  • Indices outside the list will raise an IndexError
  • Negative numbers index from the back

Example

mylist = [1, 2, 3]

mylist[-4] = 7

in operator

  • The in operator is supported on lists
  • It will return True if a given value is found in the list

Example

mylist = [1,2,3]

if 2 in mylist:
    print("The list has a 2")

List Traversal

  • A list is an iterable datatype
  • We can use for to iterate over the items in a list

Example

mylist = [1,2,3]

for i in mylist:
    print(i)

Writing List Elements

  • for is useful for reading, but doesn’t allow modification directly
  • If we need to write, we need access to an index
  • This can be achieved using len and range

Example

mylist = [1,2,3]

for i in range(len(mylist)):
    mylist[i] *= mylist[i]

print(mylist)

Exercise

Create a Python program that will add 1 to every element in a list.

Nested Lists

  • Lists can be used as list values
  • Nested lists only count as 1 element when computing len

Example

mylist = [1, 2, [3, 4, 5], 6]

print(len(mylist))

Exercise

Create a Python program that will count all individual elements in nested lists.

List Operations

List + operator

  • The + operator can be used to concatenate lists

Example

start = [1, 2]
end = [3, 4]
complete = start + end
print(complete)

Appending

  • The + operator may be used for appending
  • Single items must be represented as a list of length 1

Example

mylist = [1,2,3]

# The following will raise an exception
mylist = mylist + 4

print(mylist)

Exercise

Create a program that builds a list of 10 randomly generated numbers

Solution

import random

nums = []

for _ in range(10):
    nums += [random.randint(1,100)]

print(nums)

List * operator

  • The * operator can be used to duplicate lists

Example

mylist = [1, 2, 3]
longlist = mylist * 20
print(longlist)

Slicing

  • Lists support slicing as used with strings
  • Omitted values will be treated as the start and end of the list

Example

mylist = [1, 2, 3, 4, 5, 6]

print(mylist[1:4])
print(mylist[:4])
print(mylist[1:])

Slices in assignment

  • Slices can be used in the left hand side of an assignment

Example

mylist = [1, 2, 3, 4, 5, 6]

mylist[1:4] = [7, 8, 9]

print(mylist)

Copying Lists

  • Because lists are mutable, it can be useful to create copies
  • The copy method can be used for this
  • Slicing syntax ([:]) can also be used

Example

mylist = [1,2,3]
original = mylist.copy()

mylist = mylist + [4]

print(mylist, original)

append

  • The append method can be used to add an item to the end of a list
  • If lists are passed to append, a nested list will be created

Example

mylist = [1,2,3]

mylist.append(4)

print(mylist)

extend

  • The extend method can add many elements to a list
  • The argument passed in should be a list

Example

mylist = [1,2,3]

mylist.extend([4, 5, 6])

print(mylist)

sort

  • The sort method can be used to sort list elements in place
  • The list will be modified by this operation
  • sort always returns None

Example

mylist = [4, 1, 3, 2]

mylist.sort()

print(mylist)

In-place modification

  • It can be tempting to assign the result of sort back to the original list
  • This is not desirable, as it will replace the value with None

Example

mylist = [4, 1, 3, 2]

mylist = mylist.sort()

print(mylist)

Exercise

Create a Python program that prints the three largest numbers in a list

Deleting Elements

  • pop will remove and return an element at a position (or the last element by default)
  • del can be used to remove the element without returning it (can use slices)
  • remove will remove the element by value

pop Example

mylist = [1, 2, 3]

removed = mylist.pop(1)

print(mylist, removed)

del Example

mylist = [1, 2, 3]

del mylist[1]

print(mylist)

remove Example

mylist = [1, 2, 3]

mylist.remove(1)

print(mylist)

Exercise

Create a Python program to remove all single-digit numbers from a list

Lists

List functions

  • Many built-in functions can operate on lists
  • Examples include len, max, min, and sum

Example

mylist = [1, 2, 3, 4]

print(f"Number of values: {len(mylist)}")
print(f"Sum of values: {sum(mylist)}")
print(f"Smallest value: {min(mylist)}")
print(f"Largest value: {max(mylist)}")

Numeric lists

  • Some functions will only work properly on lists with numeric elements
  • sum won’t work properly with strings, for example

Example

mylist = ["a", "b", "c"]

print(sum(mylist))

List constructor

  • The list constructor can be used to create a list from a string

Example

items = list("abcdef")

print(type(items))
print(items)

Lists and Strings

  • A list is a sequence of arbitrary values
  • A string is different data type that represents a sequence of characters
  • They cannot always be used interchangeably

Example

items = "abc"

for letter in items:
    print(letter)

Example

items = ["a", "b", "c"]

items.split()

Objects and values

  • Two values can hold the same contents without pointing to the same object
  • Consider the following assignment:
a = 'banana'
b = 'banana'
Possible assignment results

is

  • The is operator can be used to test if two values are the same object

Example

a = 'banana'
b = 'banana'

print(a is b)

Lists

  • Because lists are mutable, a new list is a new object
  • Two lists with the same values may not be the same object

Example

a = list('banana')
b = list('banana')

print(a is b)

List equivalence

  • We can also use == to compare lists
  • This will perform a deep compare to check if the two lists have identical values

Example

a = list('banana')
b = list('banana')

print(a == b)

Exercise

Write a Python function that will return True if and only if the two lists contain the same items but are not the same list.

def equal_but_not_same(a, b):


a = [1, 2]

assert(equal_but_not_same([1, 2], [1, 2]) == True)
assert(equal_but_not_same(a, [1, 2]) == True)
assert(equal_but_not_same([1], [2]) == False)
assert(equal_but_not_same(a, a) == False)

Multiple References

  • Multiple variable can point to the same object

Example

a = [1, 2, 3]
b = a

print(a is b)

Aliasing

  • An object with more than one reference to it is aliased
  • Care must be taken when aliasing mutable objects
  • A modification to one will affect the other

Example

scores = [100, 85, 75, 87]

letter_grades = scores

for i in range(len(scores)):
    if scores[i] >= 90:
        letter_grades[i] = 'A'
    elif scores[i] >= 80:
        letter_grades[i] = 'B'
    elif scores[i] >= 70:
        letter_grades[i] = 'C'

print(letter_grades)
print(scores)

Lists as arguments

  • If a list is passed to a function, it will be aliased
  • A modification inside the list will be seen by the caller

Example

def square_all(numbers):
    """ Return a list with the squares of all numbers"""

    for i in range(len(numbers)):
        numbers[i] = numbers[i] * numbers[i]

    return numbers

mynums = [1, 2, 3, 4]

print(mynums)
print(square_all(mynums))
print(mynums)

Exercise

Adjust the following program so that first_half does not modify the list it is passed

mylist = list(range(10))

def first_half(values):
    """ Returns the first half of a list of values """
    for i in range(len(values) // 2):
        values.pop(-1)

    return values

print(first_half(mylist))
print(mylist)

Dictionaries

List

  • Lists map numbers to values
  • Lists are dense, meaning numbers from 0 up to the list length all map to a value

Dictionaries

  • Can also map numbers to values
  • Can be sparse meaning they don’t need to map all possible values
  • Created using curly braces {}

Example

values = {}

values[0] = "a"
values[2] = "b"

print(values[2])

Hashable Types

  • An object is hashable if it has a hash value which never changes during its lifetime and can be compared to other objects
  • Hashable objects which compare equal must have the same hash value
  • Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally

Dictionary Keys

  • Integers may be used as keys
  • Strings may be used as keys
  • Any other hashable type may be used as a key

Example

values = {}

values["a"] = 1
values["b"] = 2

print(values["a"])

Exercise

Create a program that builds a dictionary that maps the days of the week to the time you need to wake up on these days.

Printing Dictionaries

  • Dictionaries can be printed directly
  • They will show value mapping between curly braces {}

Example

values = {}

values["a"] = 1
values["b"] = 2

print(values)

Instantiating Dictionaries with Values

  • The output format from the previous example can be used to create new lists directly

Example

values = {"a": 1, "b": 2}

print(values)

Whitespace

  • Whitespace may be used inside dictionary declarations
  • New lines may be used to organize declarations

Example

poketypes = {
    "Charmander": "fire",
    "Squirtle": "water",
    "Bulbasaur": "grass",
}

print(f"Squirtle is {poketypes['Squirtle']} type")

in

  • The in operator can be used
  • in will return True if the key exist in the dictionary

Example

hrs = {
    "Bonds": 762,
    "Aaron": 755,
    "Ruth": 714,
}

print("Pujols" in hrs)
print("Aaron" in hrs)
print(762 in hrs)

Exercise

Create a program that can count the number of occurrences of each word in a text

text = """
  In the beginning was the Word,
  and the Word was with God,
  and the Word was God.
"""

Solution

Iterating over Dictionaries

Iterating over Keys

  • The native method to iterate over a dictionary using for will iterate over keys

Example

d = {"a": 1, "b": 2, "c": 3}

for key in d:
    print(key)

Iterating over Values

  • It is sometimes useful to access just values from a dictionary
  • The values method can be used to get values as an iterable
  • Alternatively, we can access values by their key

Example

d = {"a": 1, "b": 2, "c": 3}

for value in d.values():
    print(value)

Example

d = {"a": 1, "b": 2, "c": 3}

for key in d:
    print(d[key])

Working Problems

  • Professional developers will frequently be asked to solve simple programming tasks in interviews
  • It is important to practice these sorts of problems
  • Example problems: LeetCode, Project Euler

Lab Review

Lab 8

Tuples

Container Types

  • Strings contain a sequence of characters
  • Lists contain a sequence of values of any type
  • Dictionaries contain values of any type indexed by key

Tuples

  • Tuples contain a sequence of values
  • Values may be any type

Tuple Creation

  • Tuples are created as comma-separated values

Example

t = 1, 2

print(t)

Small Tuples

  • A one-item tuple can be created using a trailing comma t = 1,
  • An empty tuple may be created using the tuple constructor or empty parens (())

Example

single = "a",
print(single)

empty = tuple()
print(empty)

empty = ()
print(empty)

Tuple constructor

  • The tuple constructor can also be used to convert other types into tuples

Example

letters = tuple("Hello")

print(letters)

Tuple Features

  • Indexing works like lists for the most part
  • Assigning via index is not allowed (like strings)

Example

t = "a", "b", "c"

print(t[1])

t[1] = "x"

Immutability

  • The container itself is immutable
  • Mutable values (such as lists) can still be modified

Example

t = ("A", [1, 2])

print(t)

t[1].append(3)

print(t)

Destructuring Assignment

  • A destructuring assignment can be used to assign multiple values at once
  • The right hand side must be the same length as the left hand side

Example

a, b = (1, 2)

print(a)
print(b)

Example

word1, word2 = "Hello world".split()

print(word1)
print(word2)

Exercise

Write a concise program to swap the values in two variables, a and b

Tuple Comparison

  • Tuples are compared one element at a time (like strings)
  • Once a larger element is found, that tuple is considered to larger
    • Future elements are not considered

Example

smaller = (1, 3, 1000)
larger = (1, 4, 0)

print(smaller < larger)

DSU Pattern

  • Uses tuples for sorting items
  • Decorate items using a sort key
  • Sort items
  • Undecorate the items by removing the sort key

Exercise

Write a Python program that creates a list of all words in a sentence. The list should be sorted by the length of the word, smallest first. For example, the sentence “She is a girl” should produce:

['a', 'is', 'She', 'girl']

Solution

sentence = "The quick brown fox jumped over the lazy dog"

decorated = []

for word in sentence.split():
    decorated.append((len(word), word))

decorated.sort()

undecorated = []

for _, word in decorated:
    undecorated.append(word)

print(undecorated)

Tuples

Dictionary Items

  • items can be used to get keys and values from a dictionary

Example

runtimes = {
    "The Fellowship of the Ring": 178,
    "The Two Towers": 179,
    "The Return of the King": 201,
}

for kv_tuple in runtimes.items():
    print(kv_tuple)

Destructuring and for

  • Destructuring can be used to assign multiple variables in a for loop
runtimes = {
    "The Fellowship of the Ring": 178,
    "The Two Towers": 179,
    "The Return of the King": 201,
}

for movie, runtime in runtimes.items():
    print(f"{movie} is {runtime} minutes")

enumerate

  • enumerate can be used to add a count to iterable items
  • The return value from enumerate is an iterable of (count, value) tuples

Example

alphabet = "abcdefghijklmnopqrstuvwxyz"

print(list(enumerate(alphabet)))

Enumeration Loops

  • Enumeration can be used to avoid manual loops counters in certain loops

Example

alphabet = "abcdefghijklmnopqrstuvwxyz"

for letter in enumerate(alphabet):
    print(letter)

Exercise

Use enumerate to print only the letters with an even-numbered index in a string.

Modifying Lists Items

  • Enumeration can be helpful if we need a reference to list items during iteration

Example

nums = [1, 2, 3, 4, 5, 6, 7, 8]

for i, num in enumerate(nums):
    # Multiply every other value by 10
    if i % 2 == 0:
        nums[i] *= 10

print(nums)

Iterating multiple lists

  • It can be helpful to iterate multiple lists at the same time
  • This can be accomplished with an index

Example

names = ["Jordan", "Pam", "John"]
ages = ["19", "24", "23"]

for i, name in enumerate(names):
    age = ages[i]

    print(f"{name} is {age}")

zip

  • zip can be used to directly match items from two iterables
  • A new iterable is created providing tuples of items from the supplied iterators

Example

names = ["Jordan", "Pam", "John"]
ages = ["19", "24", "23"]

for pair in zip(names, ages):
    print(pair)

Example

names = ["Jordan", "Pam", "John"]
ages = ["19", "24", "23"]

for name, age in zip(names, ages):
     print(f"{name} is {age}")

Exercise

Use zip to create a list of each pair of letters in a string. For example, the string “abcd” should produce the following list:

[('a', 'b'), ('b', 'c'), ('c', 'd')]

Example

Score of a string

List Comprehensions

Creating Lists

  • We frequently want to create a list from another list
  • This can be accomplished using a for loop

Example

nums = [2, 5, 9]

squares = []

for num in nums:
    squares.append(num * num)

print(squares)

Map

  • The task of building one iterable from another is common
  • A special function called map is provided to simplify this task
  • map takes a function and applies it to all items in an iterable return a new iterable

Example

nums = [2, 5, 9]

def square(n):
    return n * n

squares = map(square, nums)

print(list(squares))

Lambda Functions

  • It can sometimes be helpful to create small, inline functions
  • The lambda keyword can be used to facilitate this

Example

double = lambda x: x * 2

print(double(4))

Exercise

Create a square function using lambda instead of def.

Map and Lambda

  • lambda and map can be combined to quickly perform operations on entire lists

Example

nums = [2, 5, 9]
squares = map(lambda n: n*n, nums)
print(list(squares))

List Comprehensions

  • The pattern of creating one list from another is very common
  • Python introduces special syntax to simplify these operations
  • This is referred to as a list comprehension

Example

nums = [2, 5, 9]
squares = [n*n for n in nums]
print(squares)

Filtering

  • Filtering can be applied to list comprehensions using an if clause

Example

nums = list(range(10))
print(nums)
big_squares = [n*n for n in nums if n > 5]
print(big_squares)

Generator Expressions

  • Work somewhat like list comprehensions
  • Produce generators instead of lists
  • Generator wait to compute values until they are needed

Example

# Don't try this with a list
# We'll run out of memory
squares = (i*i for i in range(100**100))

# Find the first square larger than a million
for square in squares:
    if square > 1000000:
        print(square)
        break

Lab 9 Review

Generator Expressions

List Comprehensions

  • List comprehensions can be used to quickly build a new list from an existing list

Example

nums = list(range(10))
odds = [n for n in nums if n % 2 == 1]

print(odds)

Generator Expressions

  • The expression inside a list comprehension is known as a generator expression
  • These can be used in other contexts

Example

nums = list(range(10))
odds = (n for n in nums if n % 2 == 1)

print(odds)

Generators

  • A generator object is an iterable that can only be iterated once
  • The object cannot be index like a list
  • Value are created just in time for their use

Example

squares = (n*n for n in range(2, 5))

print(squares)
print(next(squares))
print(next(squares))
print(next(squares))

for

  • Generator expressions can be iterated using for

Example

words = "lorem ipsum dolor sit amet".split()

first_letters = (w[0] for w in words)

for letter in first_letters:
    print(letter)

Creating Dictionaries

  • We can create dictionaries from pairs of values using the dict constructor
  • This technique can be combined with generator expressions

Example

words = ["apple", "boy", "carrot"]

letter_words = dict((w[0], w) for w in words)

print(letter_words)

Dictionary Comprehension

Example

words = ["apple", "boy", "carrot"]

letter_words = {w[0]: w for w in words}

print(letter_words)

Custom Generators

  • The yield keyword can be used to emit values from generators
  • Custom generators look like functions but maintain their state between yielding values

Example

def myrange(start, stop, step):
    i = start

    while i < stop:
        yield i
        i += step

for i in myrange(1, 10, 2):
    print(i)

Exercise

Create a generator that will yield every odd number that is not divisible by 5.

Project Overview

Web Applications

Local Applications

  • Apps created so far are accessible from the local device only
  • Basic functions (print and input) interact with the system in text mode
  • These limitation make it challenging to create modern apps

Hypertext

  • Text document with links to other text documents
  • Provides the basis for the world wide web
Hyperlinked documents

HTTP

  • Hypertext transfer protocol
  • Provides a mechanism to request hypertext documents from remote systems

Flask

  • Python package to implement HTTP servers

Example

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, world!"

URL

  • Provides a unique identifier for a hypertext document
  • Sent by a user agent as part of an HTTP request

HTML

  • Hypertext markup language
  • Domain specific language used to describe hypertext documents

Example

from flask import Flask

app = Flask(__name__)

@app.route("/page1")
def page1():
    return "Page 1 <a href=/page2>Go to page 2</a>"

@app.route("/page2")
def page2():
    return "Page 2 <a href=/page1>Go to page 1</a>"

Form Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/")
def square():
    result = ""
    if request.args.get('num'):
        result = float(request.args.get('num')) ** 2

    return f"""
        <form>
            <input name=num autofocus />
            <input type=submit value=Square />
        </form>
        {result}
    """

Extended Example

from flask import Flask, request, session
import languagemodels

app = Flask(__name__)
app.secret_key = "FyJYMJmwZUWASo5J"

@app.route("/")
def home():
    if not "history" in session:
        session["history"] = ""

    usertext = request.args.get("usertext", "")

    if usertext:
        session["history"] += f"<p>User: {usertext}"

        response = languagemodels.do(f"Respond to a user: {usertext}")
        session["history"] += f"<p>Bot: {response}"

    return f"""
        {session['history']}
        <form action=/>
        <input type=text name=usertext autofocus />
        <input type=submit />
        </form>
        """

Cyber Team Tonight

  • Professor Craton will be talking about applications of AI
  • 7 pm in Decker 346

Git

Software Size

  • One way to measure software size is via source lines of code (SLOC)
  • A modern piece of large software, such as an operating system, may have tens of millions of lines of code

Team Size

  • Some software is developed by individuals
  • Many applications are developed by large teams
  • Thousands of developers may work on large application such as Windows or the Linux kernel

How can we help thousands of people work together to write millions of lines of code?

Version Control

  • Version control systems are used to manage change to the source code of software systems
  • These tools become critical as the size of software and teams increases

Google Docs

History

  • Version control systems manage history of the codebase
  • Mistakes can be undone
  • Previous versions of the software can be used

Git

  • Distributed version control system
  • Originally developed to manage the source code of the Linux kernel
  • Most widely used version control system today

Init

  • We can create a new git repository using git init
  • This creates the .git metadata directory
  • This repository will have no commits or pointers to commits

Status

  • git status can be use to check the current state of the repository

Example

> git init
Initialized empty Git repository...
> git status
On branch main

No commits yet

nothing to commit (create/copy files and use "git add" to track)

Commits

  • At its core, git track states of the system known as commits
Git commits

Staging

  • Before files are committed, they must be staged

Add

  • git add can be used to track and stage a file

Example

> git add main.py
> git status
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   main.py

Commit

  • git commit can be used to create a new commit
  • The -m flag can be used to provide a message
  • File names can be provided
  • The -a flag will commit all changes

Log

  • git log can show the commit history
Git areas

Vacuum Lab Review

Regular Expressions

find

  • The string find method can be used to get the location of one string in another

Example

sent = "Where is the word 'the'?"

print(sent.find("the"))

split

  • The string split method can be used to split strings

Example

ip = "10.75.123.76"

octets = ip.split(".")

print(octets)

Regular Expressions

  • Available in the re module
  • Provide their own mini language for parsing strings
  • Useful for somewhat advanced string processing tasks

search

  • The re search method can be used to find a matching span in a string
  • Will return None if no match

Example

import re

zips = "46012, 46013 46014. 46015"

if re.search("46013", zips):
    print("46013 is present")

Character Matching

  • By default, regular expressions match characters literally
  • Some special character can create more complex matches
  • For example . will match any character

Example

import re

words = "cat dog fox pig"

if re.search(".ox", words):
    print("A word ending in ox was found")

Exercise

Create a regular expression that can match all 5 letter words that start with “c”

DFAs

Chomsky Hierarchy

Grammar Automaton (Computer)

Unrestricted Turing Machines Context Free Pushdown Automata Regular Finite State Automata

Regular Languages

  • Are insufficient to parse most programming languages
  • Can be processed by a simple finite automaton

Deterministic Finite Automaton (DFA)

  • Finite set of states \(Q\)
  • Finite set of input symbols called the alphabet \(\Sigma\)
  • Transition function \(\delta : Q \times \Sigma \rightarrow Q\)
  • Initial or start state \(q_0 \in Q\)
  • Set of accept states \(F \subseteq Q\)

Drawing DFAs

  • States are nodes on the graph
  • Start state indicated by arrow
  • Accept states indicated by double border
  • Transitions indicated as labeled arrows
DFA to accept string containing an even number of zeroes

Regular Expressions

Counting Characters

  • Count modifiers can be appended to character classes
  • One more more can be matched using +
  • Zero or more can be matched using *

Exercise

Create a single, concise regular expression to match a string with 0 or more a’s followed by at least 1 b followed by at least 1 c. Examples:

  • abc
  • bc
  • aabbcc

These should not match:

  • acb
  • ac

match

  • Match will return True if a string matches from the beginning

Example

import re

words = "cats"

if re.match("cat", words):
    print("The strings match")

Search

  • We have seen that regular expressions can be used for search using match or search

Example

import re

num = "1387562"

if re.search("7", num):
    print("Number includes a 7")

Data Extraction

  • Regular expressions can be used to extract many matches
  • The findall function can be used for this purpose

Example

import re

message = "My number is 7655551234 and his is 7655556789"

numbers = re.findall("765.......", message)

for number in numbers:
    print(number)

Metacharacters

  • Certain characters, such as . are not matched literally
  • The full list of metachars is:

. ^ $ * + ? { } [ ] \ | ( )

Character classes

  • We can search for groups of characters to match against a single character using []
  • We can use “-” to indicate a range of characters

Example

import re

message = "Hi, alice@example.com. My email is bob@example.com"

emails = re.findall("[a-z]+@[a-z]+.com", message)

for email in emails:
    print(email)

Common Classes

  • \d - any decimal digit
  • \s - any whitespace
  • \S - any non-whitespace
  • \w - any alphanumeric

Example

import re

text = "What is 123 + 456?"

nums = re.findall("\d+", text)

print(nums)

Fuzzy matching

  • We can use more permissive expressions to capture values in multiple formats

Example

import re

phone_nums = """
(765) 555 1234
317-555-6789
76555551357
"""

matches = re.findall("[\d\(\)\- ]+", phone_nums)

print(matches)

Substitutions

  • sub can be used to perform regex replacements

Example

import re

phone_nums = """
(765) 555 1234
317-555-6789
76555551357
"""

matches = re.findall("[\d\(\)\- ]+", phone_nums)

cleaned = [re.sub("[ \-\(\)]", "", m) for m in matches]

print(cleaned)

Extraction

  • Parens () can be used to indicate which portion of an expression to extract

Example

import re

text = "1234515a5"

print(re.findall("(.)5", text))

Exact counts

  • Brackets {} can be used to specify an exact count on the preceding character class

Example

import re

text = "46012 765 46013"

zips = re.findall("\d{5}", text)

print(zips)

Example

import re

addresses = """
Anderson, IN
Chicago, IL
Indianapolis, IN
"""

cities = re.findall("(.*), [A-Z]{2}", addresses)

print(cities)

Match Objects

  • search returns a match object on success
  • Groups can be extracted from the match

Example

import re

text = "a1 b2 c3"

match = re.search("b(\d)", text)

print(match.groups())
print(match.group(1))

Group 0

  • Match group 0 is always the full match

Example

import re

text = "cat dog bat"

match = re.search("b([a-z])t", text)

print(match.group(0))

More RE Information

Advent of Code

Command Line Interfaces

CLI

  • A CLI is a way to interact with a computer by providing lines of text instructions
  • Began to replace punched cards in the 60s as a way to interact with computers
Punched Card
Teletype

Terminal

  • Hardware devices used to send and receive text from a computer
  • Includes text output and text input
  • Modern systems may include virtual terminals
Computer Terminal

Python REPL

  • Accepts and runs Python commands

Example

>>> a = 5
>>> b = 7
>>> a + b
12

Shell

  • Provides an interface to the underlying operating system
  • Shells may be graphical or text-based

Example

  • Windows without Explorer

Text shells

  • Many operating systems provide a text-based shell
  • Examples include cmd (Windows), Powershell (Windows), and BASH (Unix, Linux, and MacOS)

Command Format

Prompt command param1 param2 … paramN
  • Commands are generally entered following a prompt
  • Commands may be internal or call an external program
  • Parameters are provides by the user for the command

Working Directory

  • Running programs (processes) have a current working directory used to resolve relative paths
  • The shell may allow the working directory to be changed

Changing Directories

cd /home/user/documents

Listing current directory

  • It is frequently helpful to be able to list the current directory
  • The ls command can be used for this in most shells
  • Some shells may use dir

Running a program

  • One of the key features of a shell is launching programs
  • This is accomplished using commands in text-based shells

Example

Run calculator using Windows:

C:\> calc

Run thonny using Bash:

> thonny

Lab 11 Review

Objects

What is an object?

  • Any data with state (attributes or value) and defined behavior (methods)

Common Objects

  • str
  • int
  • list
  • range

State

  • Objects are containers for state and behavior
  • They may have a value
  • They may have attributes

Functions

  • Functions are containers for behavior
  • They do not typically also store state

Attribute and Method Access

  • Attributes and methods are accessed using “.

Attribute Example

r = range(1, 10, 2)

print(r.start)
print(r.stop)
print(r.step)

Methods

  • A function that is a member of an object
  • When called as an attribute of an object, the function can operate on the object state

Method Example

l = [3, 1, 4, 2, 5]

l.sort()

Class

  • A template for creating user-defined objects
  • Class definitions normally contain method definitions which operate on instances of the class
  • Class names are written in upper camel case by convention

Example

class Player:
    hp = 100

alice = Player()
print(alice.hp)

Exercise

Create a Student class with class_level and gpa attributes

Methods

  • Functions defined in the class body become attached to objects
  • When called, these have access to the object instance

Example

class Vehicle:
    speed = 0

    def accelerate(self):
        self.speed += 1

car = Vehicle()
car.accelerate()
print(car.speed)

Exercise

Add a set_gpa method to your Student class that will set their GPA to a supplied number

Constructor

  • A special method may be called when creating a new object from a class
  • This is called the constructor

Example

class Length:
    def __init__(self, meters):
        self.meters = meters
        self.feet = meters * 3.2808

l = Length(2)
print(l.feet)

self

  • The first argument passed to a method will be a reference to the object instance
  • self is chosen as the name for this parameter by convention

Exercises