knowledge-kitchen

Midterm Review - Introduction to Computer Programming (No Slides, Please)

This document has been autogenerated from slides.


Intro to Computer Programming in Python

The most critical details of each concept covered before Exam 1:

  1. Exam Format
  2. Basic Computer Concepts
  3. Variables, Literals & Expressions
  4. Input & Output
  5. Data Types
  6. Strings
  7. Boolean Logic
  8. Decision-Making
  9. Flow Charts
  10. Functions
  11. Modules
  12. The __name__ Guard
  13. Program Structure

Exam Format

What to expect

The exam is a mix of two familiar formats — the same tools you’ve used all semester:

There’s nothing new to learn about how to take the exam — only the concepts to review.

When & where

The exam takes place during our regular class meeting — nothing changes about the logistics:

How to prepare

You are required to attempt the Practice Exam Materials listed on the course schedule:

Completing both is the best way to know what to expect and where to focus your review.

Basic Computer Concepts

Files & folders

All data on a computer is stored in files, organized into folders (a.k.a. “directories”).

Text files vs. binary files

There are two fundamental kinds of files:

Your source code is a text file. Write it in a real text editor like Visual Studio Code — not a word processor like Microsoft Word or Google Docs, which add invisible formatting data.

What makes a file “plain text”?

A plain text file contains nothing but text characters and line breaks:

Under the hood, the characters are stored as numbers using a mapping scheme like ASCII or Unicode (e.g. F → a specific number) — but the file holds only those character codes, nothing else.

Code files are text files

The source code you write in any programming language is always a plain text file.

Because code is plain text, you edit it with a text editor — a program that deals exclusively with plain text. A code editor is a text editor.

File names

Follow “lowest common denominator” conventions so your files work on any computer:

File extensions

A file extension is the suffix after the . in a file name (e.g. program.py).

The working directory

At any moment, your program (or file browser, or command line) is “looking at” exactly one folder — the current working directory.

Variables, Literals & Expressions

Variables

A variable is a symbol that represents data stored in memory.

x = 3
y = x + 1   # y becomes 4
my_name = "Inigo Montoya"

Literals vs. variables

A literal is a value written directly (literally) into the code.

lucky_number = 4        # 4 is an integer literal
print(lucky_number + 666)  # lucky_number is a variable, 666 is a literal

Expressions

An expression is any code that evaluates to a single value.

Naming conventions & dynamic typing

Variable names cannot contain spaces or special characters. Common styles:

Python is dynamically typed — a variable’s type is determined at runtime and can change:

i = 100
i = "this is not an integer anymore!"   # perfectly fine in Python

(In statically-typed languages like Java or C, this would be an error.)

Input & Output

Receiving input

The input() function solicits input from the user (the keyboard, i.e. “standard input”).

name = input("What's your name? ")
print("Welcome, " + name)

Critical: input() always returns a string — even if the user types a number.

age = input("Enter your age: ")   # a string, e.g. "20"
age_as_int = int(age)             # must convert to do math
dog_years = age_as_int * 7

Sending output

The print() function sends text output to the console (“standard output”).

print("hello", end="")          # no newline
print("this", end="-")          # "this-"
print("hello", "world!")            # "hello world!"
print("hello", "world!", sep="-")   # "hello-world!"

Data Types

Primitive data types

Aggregate data structures

Type incompatibilities

You cannot mix incompatible types in an operation:

x = "my favorite number "
y = 4
z = x + y          # ERROR! can't add a string to an int
z = x + str(y)     # fine — convert the int to a string first

Converting & inspecting types

Conversion functions:

Introspection — discovering a value’s type:

Strings

Defining & combining strings

In Python, single, double, or triple quotes all work:

'bla'   "bla"   '''bla'''   """bla"""
'bla' + ' ' + 'bla'   # 'bla bla'
'bla ' * 3            # 'bla bla bla '

Indexing & slicing

Index numbers always start at 0; negative indices count from the end.

'fabrication'[3]      # 'r'  (the 4th character)
'fabrication'[-8]     # 'r'
'fabrication'[2:6]    # 'bric'  (a slice / substring)

Strings are immutable — you cannot change a character in place:

s = 'fabrication'
s[1] = 'o'    # ERROR

Escape characters

Written with a backslash, each represents a single character:

"hello\nworld"   # prints on two lines

Raw strings

A raw string (prefix r) treats backslashes literally — no escape meaning.

Useful when a string has many backslashes (e.g. file paths, regular expressions):

# hard to read with escaped backslashes:
caput = 'C:\\Program Files\\Internet Explorer'

# easier as a raw string:
less_caput = r'C:\Program Files\Internet Explorer'

Useful string methods

Return Booleans: .startswith(), .endswith(), .islower(), .isupper(), .isnumeric(), .isalpha()

Search & modify (return a new string): .find(), .replace(), .strip(), .count()

Change case (return a new string): .lower(), .upper(), .capitalize(), .title()

Membership — the in operator returns a Boolean:

'smack' in 'lipsmackingly good'   # True

Formatting strings

The modern, preferred way is the f-string (prefix f):

first, second = 'a', 'b'
x = f'{first}, {second}'   # 'a, b'

Format specifiers control alignment, decimals, and more:

f'{0.33333:.2f}'        # '0.33'   (2 decimal places)
f'{5200:,d}'            # '5,200'  (commas for thousands)
f'{0.52:.0%}'           # '52%'    (percentage)
f'{"Harry":>20}'        # right-aligned within 20 spaces

(Older syntax: '{}'.format(...) and format(value, spec).)

Boolean Logic

Boolean values & operators

Every Boolean expression evaluates to one of two values: True or False.

Logic operators combine/flip Boolean values:

if feeling == "lazy" or overworked == True:
    print("Take the day off!")

if not this_is_fun:
    print("Then why are you doing this?")

Comparison operators

These always result in a Boolean value:

5 == 5        # True
"A" == "B"    # False
5 != 5        # False

Note: = is assignment; == is comparison. Don’t confuse them!

Decision-Making

if / elif / else

Decision-making (a.k.a. selection, branching, conditionals) lets a program choose what to do based on Boolean conditions.

x = input("What is your favorite fruit?")

if x == "orange":
    print("Yes, oranges are very nice")
elif x == "apple":
    print("boring")
elif x == "strawberry":
    print("not in season")
else:
    print("never heard of it")

How it flows

Combine conditions with Boolean operators, and remember to convert input types:

temp = int(input("What's the temperature?"))
if (precipitation == "rain" or precipitation == "drizzle") and (temp >= 5 and temp <= 60):
    print("Wear a rain jacket, please!")

Flow Charts

Diagramming program logic

Flow charts diagram the flow/logic of a program using standard shapes:

Functions

Defining & calling

A function is a modular, reusable block of code stored in memory to run later.

Define with def — note the indented body:

def say_hello():
    print("hello")

Defining a function does not run it. You must call it:

say_hello()   # outputs "hello"

Parameters & arguments

Functions can accept input through parameters:

def say_hello(person):
    print("hello, " + person)

say_hello("Martha")   # outputs "hello, Martha"
def do_something(parameter1, parameter2):
    ...
do_something("hello", 100)

Return values

A function can return a result to the code that called it, using return:

def add_one(some_number):
    new_number = some_number + 1
    return new_number

result = add_one(10)   # result is 11
print(result)

The returned value can be stored in a variable or used in an expression.

Functions calling functions

Functions can call other functions — this is how we build programs from small, reusable pieces.

def square(n):
    return n * n

def sum_of_squares(a, b):
    return square(a) + square(b)   # calls square() twice

print(sum_of_squares(3, 4))        # 9 + 16 = 25

sum_of_squares() delegates part of its work to square() — each function does one small job.

The call stack

When one function calls another, the program pauses the caller, runs the callee, then returns to exactly where it left off. These paused calls form a stack:

def greet(name):
    message = build_message(name)   # 2. pause greet, run build_message
    print(message)                  # 5. resume greet, print result

def build_message(name):
    polite = add_title(name)        # 3. pause build_message, run add_title
    return "Hello, " + polite       # 4. resume, return to greet

def add_title(name):
    return "Dr. " + name            # runs first to completion, returns

greet("Watson")                     # 1. the program calls greet

The call stack, visualized

As calls are made, they stack up; as each return fires, they unwind in reverse order:

greet("Watson")
└─ build_message("Watson")
   └─ add_title("Watson")  →  returns "Dr. Watson"
   ←  returns "Hello, Dr. Watson"
←  prints "Hello, Dr. Watson"

The __name__ Guard

What it looks like

A pattern you’ll see at the bottom of well-structured Python programs:

def dog_years():
    ...

if __name__ == "__main__":
    dog_years()

It runs dog_years() only when this file is run directly — not when the file is imported into another file as a module.

How it works

Python automatically sets a special built-in variable named __name__ in every file:

So if __name__ == "__main__": is really asking: “Am I the file being run directly?”

Why we use it

A .py file can serve two roles: a program to run, and a module of reusable functions to import elsewhere.

It lets the same file be both runnable and importable — a cornerstone of good program structure.

Modules

What is a module?

A module is a file of ready-made variables, functions, and classes you can import into your program. (Other languages call these libraries, APIs, or frameworks.)

Importing & using modules

Two ways to import:

import random              # import the whole module
from random import *       # import its contents directly

How you call the functions depends on how you imported:

# with "import random":
x = random.randint(1, 100)

# with "from random import *":
x = randint(1, 100)

Common modules

import random
x = random.randint(10, 20)   # an int between 10 and 20, inclusive

Input from the internet: urllib.request

Input doesn’t only come from the keyboard — the built-in urllib.request module lets a program fetch a document from the web to use as input.

import urllib.request

# request a web page and store the server's response
response = urllib.request.urlopen("http://python.org/")

# read the response into a variable
page_data = response.read()

# now the web page's content is input to our program
print(page_data)

Making sense of web pages: BeautifulSoup

A fetched web page is just a big string of HTML. The BeautifulSoup add-on module parses that HTML so you can pull out the parts you want.

import urllib.request
from bs4 import BeautifulSoup

# fetch the page, then read its HTML
response = urllib.request.urlopen("http://python.org/")
html = response.read()

# parse the HTML into a searchable structure
soup = BeautifulSoup(html, "html.parser")

print(soup.title.string)        # the page's <title> text

for p in soup.find_all("p"):    # loop through every <p> paragraph
    print(p.string)

Built-in vs. add-on, side by side

These two slides together show the typical web-input workflow: fetch, then parse.

Together they turn a live web page into usable input for your program.

Program Structure

Putting it all together

The concepts above combine into a clean, conventional way to structure a program:

A well-structured program

def get_name():
    return input("What's your name? ")

def build_greeting(name):
    return "Hello, " + name + "!"

def main():
    name = get_name()                 # call a helper function
    greeting = build_greeting(name)   # call another helper function
    print(greeting)

if __name__ == "__main__":
    main()

main() orchestrates the program; the helper functions do the detailed work.

Splitting work across files

Helper functions are often defined in other files, which act as modules you import — keeping each file focused and its functions reusable.

# greetings.py  — a module of reusable functions
def build_greeting(name):
    return "Hello, " + name + "!"
# main.py  — the program that uses the module
import greetings

def main():
    print(greetings.build_greeting("Watson"))

if __name__ == "__main__":
    main()

Why structure programs this way?

Good luck on the exam!

Review the linked Notes for full details and examples.