11 Appendix A: Fundamentals of Python Programming
An introduction to essential Python fundamentals required to understand the code in Chapters 1-6. This appendix assumes no prior programming experience and covers the core language features needed before engaging with scientific computing libraries.
11.1 Part 1: Basic Data Types and Printing
Before working with collections or control flow, you need to understand Python’s two most fundamental data types — integers and strings — and how to display them using print(). These building blocks appear in virtually every Python program.
11.1.1 Integers
An integer (int) is a whole number with no decimal point. Python handles integers of any size without special configuration.
How the code works: - Assigning any whole number to a variable automatically makes it an int - Arithmetic operators (+, -, *, //, %, **) all work on integers - type() returns the data type of any variable — useful when debugging
11.1.2 Strings
A string (str) is a sequence of characters enclosed in single or double quotes. Strings hold text, labels, file paths, and any other non-numeric data.
How the code works: - Single quotes '...' and double quotes "..." are interchangeable - len() returns the number of characters in the string - isinstance(value, type) checks whether a variable belongs to a given type
11.1.3 Printing Variables with Strings: the f-string
The cleanest way to combine variables and text inside a print() statement is the f-string (formatted string literal). Prefix the opening quote with f and wrap any variable or expression in curly braces {}:
How the code works: - The f prefix activates expression evaluation inside {...} - Any valid Python expression can go inside the braces: variables, arithmetic, function calls - Format specifiers after : control display — :.1f means one decimal place for a float - f-strings are far more readable than string concatenation with +
Quiz: Integer and String Types
What does the following code print?
x = 42
label = "answer"
print(type(x) == int, type(label) == str)
Quiz: f-string Output
What is the output of this code?
city = "Paris"
year = 2024
print(f"{city} hosted the Olympics in {year - 4}.")
Code Challenge Quiz: f-strings
Using the variables already defined, write a print() statement using an f-string so the output is exactly:
My name is Jordan and I am 22 years old.
When you’re done, click Run Code to check your answer.
11.2 Part 2: Core Python Data Structures
11.2.1 Understanding Python Data Types
Python has several built-in data types that allow you to store and organize information in different ways. Understanding when to use each data type is crucial for writing effective code.
Video Resource: Watch this overview of Python’s data types: Python Data Types on YouTube
Overview of Python Data Types:
Python organizes data types into several categories:
- Numeric Types:
int(integers like 5, -10),float(decimals like 3.14),complex(numbers with imaginary parts) - Sequence Types:
list(ordered, mutable),tuple(ordered, immutable),str(text) - Mapping Type:
dict(key-value pairs, unordered but organized by keys) - Set Types:
set(unordered, unique elements),frozenset(immutable set) - Boolean Type:
bool(True or False)
Each data type serves a specific purpose. Lists are great for collections you want to modify. Tuples are perfect for fixed-size collections. Dictionaries organize information by meaningful keys. Sets are useful for removing duplicates or checking membership. Understanding which to use makes your code cleaner and more efficient.
11.2.2 Lists
A list is an ordered collection of items that can be of any type. Lists are mutable, meaning you can change, add, or remove items after creating them.
Creating and Accessing Lists
How the code works: - We create lists using square brackets [...] with items separated by commas - We access individual items using indexing with square brackets: list[index] - Python uses zero-based indexing, meaning the first element is at index 0
Quiz: Creating and Accessing Lists
What is the output of this code?
fruits = ["apple", "banana", "cherry"]
print(fruits[1])
Negative Indexing and Slicing
How the code works: - Negative indices count backward: -1 is the last element, -2 is second-to-last - Slicing uses the syntax [start:stop:step] - The stop index is exclusive (not included in the result) - Omitting start, stop, or step uses defaults (beginning, end, or 1)
Quiz: Negative Indexing and Slicing
What does numbers[-2:] return from the list [10, 20, 30, 40, 50]?
List Methods
How the code works: - Each method performs a specific operation on the list - append() and extend() add items (one item vs. multiple items) - insert() adds at a specific position - remove() removes by value, pop() removes by index - index() finds where a value is located
Quiz: List Methods
After running this code, what is the value of colors?
colors = ["red", "green"]
colors.append("blue")
colors.extend(["yellow"])
List Comprehension
How the code works: - List comprehension creates a new list in a single line - Syntax: [expression for item in iterable] - Can add conditions: [expression for item in iterable if condition] - More concise and often faster than loops
Iterating Through Lists
How the code works: - for item in list: iterates through each item - enumerate() provides both the index and value - The variable after for is assigned each item in turn —
Quiz: Creating and Accessing Lists
What is the output of this code?
fruits = ["apple", "banana", "cherry"]
print(fruits[1])
Quiz: Lists
What is the key characteristic of lists in Python?
11.2.3 Tuples
A tuple is an ordered collection like a list, but it is immutable—once created, you cannot change its contents.
Creating and Using Tuples
How the code works: - Tuples use parentheses (...) instead of square brackets - Single-item tuples need a trailing comma (42,) to distinguish from parentheses - Indexing and slicing work exactly like lists
Tuple Immutability
How the code works: - Attempting to modify a tuple raises a TypeError - This immutability is useful for protecting data that shouldn’t change
Quiz: Tuple Immutability
What happens when you try to run this code?
coords = (10, 20)
coords[0] = 15
Tuple Unpacking
How the code works: - Unpacking assigns each element of a tuple to a variable - The number of variables must match the number of elements - Parentheses can be omitted: x, y = coordinates works the same
Quiz: Tuples
What happens when you try to modify a tuple?
11.2.4 Dictionaries
A dictionary stores key-value pairs, where you access values by their keys rather than by index.
Creating and Accessing Dictionaries
How the code works: - Dictionaries use curly braces {key: value, ...} - Access values with dict[key] using square brackets - The .get() method is safer—it returns a default value if the key doesn’t exist
Modifying Dictionaries
How the code works: - Assign to a key to add or modify: dict[key] = value - Use del to remove a key-value pair - Use in to check if a key exists
Quiz: Dictionary Key-Value Access
What does this code print?
student = {"name": "Alice", "age": 20, "grade": "A"}
print(student["age"])
Iterating Through Dictionaries
How the code works: - Iterating over a dictionary by default gives you keys - .items() gives you both keys and values as tuples - .keys() and .values() return the keys and values separately
Quiz: Dictionaries
What is the primary advantage of using dictionaries?
11.2.5 Sets
A set is an unordered collection of unique items. Sets are useful for removing duplicates and performing set operations.
Creating and Using Sets
How the code works: - Sets use curly braces {...} but without key-value pairs - Duplicate values are automatically removed - Creating a set from a list is a quick way to remove duplicates
Set Operations
How the code works: - in operator checks if an element exists in the set - | performs union (all elements) - & performs intersection (common elements) - - performs difference (elements only in first set)
Quiz: Sets
What are the two defining characteristics of sets?
11.3 Part 3: Control Flow and Conditionals
Video Resource: Watch this visual explanation of Python booleans and conditionals: Python Booleans and Conditionals - Visually Explained
11.3.1 Conditional Statements
Conditional statements allow your code to make decisions based on conditions.
If, Elif, Else
How the code works: - if condition: executes if the condition is true - elif condition: (else-if) checks another condition if the first is false - else: executes if none of the previous conditions are true - Conditions are indented (usually 4 spaces)
Comparison and Logical Operators
How the code works: - Comparison operators return True or False - and: both conditions must be true - or: at least one condition must be true - not: inverts the condition
Membership Testing
How the code works: - in checks if an item exists in a collection - not in checks if an item does NOT exist
Quiz: Control Flow and Conditionals
What is the output of this code?
age = 16
if age >= 18:
print("You are an adult")
else:
print("You are a minor")
11.3.2 Loops
A loop repeats a block of code multiple times. Python has two loop types: for loops (repeat over a known sequence) and while loops (repeat as long as a condition is true).
for Loops
A for loop iterates over any sequence — a range of numbers, a list, or any other collection. Each iteration assigns the next item to the loop variable.
How the code works: - range(5) produces the integers 0, 1, 2, 3, 4 — the loop variable i takes each value in turn - Iterating a list assigns each element in order to the loop variable - enumerate() yields (index, value) pairs — useful when you need both the position and the item
while Loops
A while loop keeps running as long as its condition remains True. Use it when you don’t know in advance how many iterations are needed.
How the code works: - The condition count > 0 is checked before each iteration; when it becomes False the loop stops - The count -= 1 line is essential — without it the loop would run forever (infinite loop) - The second loop uses and to stop on whichever condition triggers first
Loop Control: break, continue, pass
Three keywords let you alter a loop’s normal execution:
How the code works: - break exits the entire loop as soon as the condition is met - continue jumps straight to the next iteration, skipping any remaining code in the current one - pass is a no-op — Python requires at least one statement in a block; pass fills that role
Quiz: Loops
What does the following code print?
for i in range(3):
if i == 1:
continue
print(i)
Code Challenge Quiz: For Loops
The list numbers is already defined. Write a for loop that prints each number multiplied by 2 so the output is exactly:
2
4
6
8
10
When you’re done, click Run Code to check your answer.
11.4 Part 4: Functions
Video Resource: Watch this visual explanation of Python functions: Python Functions - Visually Explained
11.4.1 Defining and Calling Functions
Functions allow you to write reusable blocks of code.
Basic Function Definition
How the code works: - def function_name(parameters): defines a function - Parameters are variables that receive values when called - Indented code is the function body - Call a function by using its name with parentheses and arguments
Quiz: Functions
What does this code print?
def add(x, y):
return x + y
print(add(5, 3))
11.4.2 Return Values
Functions can return values to the calling code.
Returning Single and Multiple Values
How the code works: - return value sends a value back to where the function was called - Multiple values separated by commas are returned as a tuple - Returned values can be assigned to variables - Functions without a return statement return None
Quiz: Return Values
What does this code print?
def get_sum(a, b):
total = a + b
return total
result = get_sum(3, 4)
print(result)
11.4.3 Function Parameters
Functions can have different types of parameters.
Positional and Default Parameters
How the code works: - Positional parameters must be provided in the same order - Default parameters have a default value if not provided - You can override a default by providing a value
Keyword Arguments
How the code works: - Keyword arguments use parameter=value syntax - Keyword arguments can be in any order - All positional arguments must come before keyword arguments
Quiz: Function Parameters
What does this code print?
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alice")
greet("Bob", "Hi")
11.4.4 Variable Scope
Understanding where variables exist and can be accessed is important.
Local and Global Variables
How the code works: - Global variables are defined outside all functions - Local variables are defined inside a function - Local variables only exist while the function is running - Each function has its own local scope
Quiz: Variable Scope
What does this code print?
x = 10
def my_function():
x = 20
print(x)
my_function()
print(x)
The Global Keyword (Use Sparingly)
How the code works: - The global keyword lets you modify a global variable from inside a function - This can make code hard to understand; usually avoid it - Better to pass values as parameters and return new values
11.4.5 Documentation and Clarity
Good code includes documentation and uses clear naming.
Docstrings and Comments
How the code works: - Docstrings (triple-quoted strings) document what a function does - Comments (lines starting with #) explain why code does something - Type hints can be added (shown next)
Quiz: Documentation and Clarity
What is the purpose of a docstring?
def calculate_area(radius):
"""Calculate the area of a circle."""
return 3.14159 * radius ** 2
Type Hints
How the code works: - Type hints use the syntax parameter: type and -> return_type - They document what types are expected - Python doesn’t enforce them; they’re helpful for code clarity
11.4.6 Lambda Functions
Lambda functions are small, anonymous functions useful for simple operations.
Creating and Using Lambda Functions
How the code works: - Lambda syntax: lambda parameters: expression - Lambdas return the value of the expression - Useful for simple, one-time-use functions
Quiz: Lambda Functions
What is the output of this code?
square = lambda x: x ** 2
print(square(5))
Lambda with Map and Filter
How the code works: - map() applies a function to each item and returns results - filter() keeps items where the function returns True - List comprehensions often accomplish the same thing more clearly
11.5 Part 5: String Operations and Formatting
Video Resource: Watch this visual explanation of Python strings: Python Strings - Visually Explained
11.5.1 String Basics
Strings are sequences of characters.
Creating and Basic Operations
How the code works: - Strings can use single or double quotes - Triple quotes allow multi-line strings - + concatenates (joins) strings - * repeats a string
Quiz: String Basics
What is the output of this code?
text = "hello"
print(text[1])
String Methods
How the code works: - String methods don’t modify the original (strings are immutable) - They return a new string with the changes - split() breaks a string into a list - join() combines a list into a string - Methods are called with a dot: string.method()
Quiz: Strings
What is special about the string text = "hello"?
11.5.2 String Formatting for Output
There are several ways to format strings in Python.
F-strings (Modern Approach)
How the code works: - F-strings use f"..." prefix - {expression} evaluates the expression - {value:.2f} formats a float with 2 decimal places - {value:10s} right-aligns a string in 10 characters - {value:3d} formats an integer in at least 3 characters
Quiz: String Formatting for Output
What does this code print?
name = "Alice"
age = 25
print(f"Name: {name}, Age: {age}")
The .format() Method
How the code works: - {} is a placeholder - .format() fills in the placeholders - Can use positional or named arguments
Basic Print Usage
How the code works: - print() separates items with spaces by default - sep="" parameter changes the separator - end="" parameter changes the ending character
11.5.3 Practical Examples
Real-world string formatting examples.
How the code works: - < left-aligns, > right-aligns within a field width - Useful for creating tabular output - Error messages with formatted values are more helpful
Quiz: Practical String Formatting Examples
What is the output?
value = 3.14159
print(f"Pi = {value:.2f}")
11.6 Part 6: Exception Handling
11.6.1 Understanding Exception Handling
Exception handling is a critical skill for writing robust Python code. Rather than allowing your program to crash when an error occurs, exception handling lets you detect, respond to, and recover from errors gracefully.
Video Resource: Watch this comprehensive introduction to exception handling: Python Exception Handling on YouTube
The Purpose of Exception Handling:
Exception handling serves several critical purposes in software development:
Prevents Program Crashes: Without exception handling, a single error (like dividing by zero or accessing a non-existent file) crashes your entire program. Exception handling lets you catch these errors and handle them gracefully.
Provides User-Friendly Error Messages: Instead of cryptic system errors, you can provide clear, helpful messages explaining what went wrong and how to fix it.
Enables Recovery and Fallback Logic: When an error occurs, you can execute alternative code. For example, if a file can’t be opened, you might create a default file or use a default dataset.
Logs and Monitors Errors: In larger applications, exception handling lets you log what went wrong for debugging and analysis, helping you improve your code over time.
Ensures Resource Cleanup: The
finallyblock guarantees that cleanup code (like closing files or releasing memory) runs even when errors occur, preventing resource leaks.
In video terms: the try block is your “attempt,” the except block is your “safety net,” and the finally block is your “cleanup crew.” Together, they keep your program running smoothly even when things go wrong.
11.6.2 Basic Exception Handling
Exceptions allow graceful handling of errors.
Try-Except-Finally Structure
How the code works: - try: contains code that might raise an exception - except ExceptionType: handles a specific exception type - finally: runs regardless of whether an exception occurred - Multiple except blocks handle different exception types
11.6.3 Common Exceptions
Understanding common Python exceptions.
How the code works: - Each exception type indicates a different kind of error - Catching specific exceptions allows targeted error handling - Understanding exception types helps you write better error messages
11.6.4 Raising Exceptions
You can raise exceptions in your own code.
How the code works: - raise ExceptionType("message") raises an exception - Useful for input validation - The as e syntax captures the exception object - The exception message provides useful context
11.6.5 Practical Use Cases
Real-world exception handling patterns.
How the code works: - Input validation prevents invalid data from causing problems - Error messages help users understand what went wrong - Graceful error handling allows programs to continue running
Quiz: Exception Handling Practical Use
What does this code print?
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return None
result = safe_divide(10, 0)
print(result)
11.6.6 5.5 Quiz: Test Your Understanding of Exception Handling
Quiz: Understanding Try-Except-Finally
What happens when this code runs?
try:
value = int("abc")
result = 100
except ValueError:
print("Error: Cannot convert to integer")
result = None
finally:
print("Done")
Quiz: Understanding When Finally Runs
What gets printed when this code runs?
try:
file = open("nonexistent.txt", "r")
except FileNotFoundError:
print("Error: File not found")
finally:
print("Cleanup complete")
11.7 Part 7: Debugging and Problem-Solving
11.7.1 Debugging Techniques
Finding and fixing bugs in your code.
Print Debugging
How the code works: - Adding strategic print statements helps trace code execution - Shows values at key points in the code - Remove or comment out after debugging
Using Assertions
How the code works: - assert condition, "message" stops execution if condition is false - Useful for catching bugs during development - Shouldn’t be used for user input validation (use exceptions instead)
Checking Variable Types and Values
How the code works: - type() returns the data type - isinstance() checks if something is a specific type - hasattr() checks if an object has an attribute - These help understand what went wrong
11.7.2 Common Errors and How to Fix Them
Recognizing and fixing common mistakes.
How the code works: - Each error type points to a specific problem - Understanding the error message helps you find the fix - Using defensive programming (checking before accessing) prevents errors
11.7.3 Reading Error Messages
Error messages tell you what went wrong and where.
How the code works: - Error messages have three main parts: type, message, and location - The traceback shows the function call stack - Use this information to identify and fix the bug
Quiz: Debugging Techniques
Which is the best approach to debug code?
11.8 Part 8: Object-Oriented Programming (OOP) Basics
11.8.1 Classes and Objects: Introduction
Classes are blueprints for creating objects.
Creating a Simple Class
How the code works: - class ClassName: defines a class - __init__ is the constructor, called when creating an object - self refers to the specific object being created - Each object has its own attributes (name, age)
11.8.2 Attributes and Methods
Objects contain data (attributes) and functions (methods).
Adding Methods to a Class
How the code works: - Methods are functions defined inside a class - self.attribute accesses the object’s data - Methods can modify the object’s state - Call methods with object.method()
Quiz: Attributes and Methods
What is the difference between an attribute and a method?
11.8.3 Toy Example: Animal Class
A more complete example showing OOP concepts.
Complete Animal Class Example
How the code works: - __init__ initializes all attributes - describe() returns information about the animal - have_birthday() modifies the age attribute - make_sound() is a method that can be customized
11.8.4 Instance vs. Class Level
Understanding the difference between instance and class attributes.
How the code works: - Class attributes are defined outside __init__ and shared by all instances - Instance attributes are defined in __init__ and unique to each object - Class attributes are accessed with ClassName.attribute - Instance attributes are accessed with self.attribute
Quiz: Object-Oriented Programming
What is the output of this code?
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def have_birthday(self):
self.age += 1
return f"{self.name} is now {self.age}"
def describe(self):
return f"{self.name} is a {self.age}-year-old dog"
my_dog = Dog("Buddy", 3)
print(my_dog.have_birthday())
print(my_dog.describe())
11.8.5 When to Use Classes
Understanding when OOP is useful.
How the code works: - Use classes when you have data and related operations - Classes help manage state (data that changes) - Don’t overuse classes; simple functions are fine for simple tasks - Classes become more valuable as complexity increases
11.9 Part 8: Import Statements
11.9.1 Basic Imports
Importing and using modules.
How the code works: - import module imports the entire module - from module import function imports specific items - import module as alias creates a shorter name - Accessed with module.function() or directly if imported with from
Quiz: Basic Imports
What is the output of this code?
import math
print(math.sqrt(16))
11.9.2 Using Imported Modules
Understanding what modules contain.
How the code works: - dir(module) shows what’s available in a module - help(function) shows documentation - These tools help you learn what a module offers
Quiz: Imports and Modules
What is the difference between these two approaches?
# Approach 1
import math
result = math.sqrt(16)
# Approach 2
from math import sqrt
result = sqrt(16)
11.9.3 Organizing Imports
Best practices for importing.
How the code works: - Group imports by type: standard library, third-party, local - This organization makes code readable - Helps identify dependencies at a glance
11.10 Exercises
11.10.1 Part 1: Data Structures
List Exercises
Exercise 1.1.1: List Indexing and Slicing
Exercise 1.1.2: List Methods
Tuple Exercises
Exercise 1.2.1: Tuple Unpacking
Exercise 1.2.2: Using Tuples in Functions
Dictionary Exercises
Exercise 1.3.1: Dictionary Operations
Exercise 1.3.2: Iterating Dictionaries
11.10.2 Part 2: Control Flow
Conditional Exercises
Exercise 2.1.1: If-Elif-Else
Exercise 2.1.2: Logical Operators
Loop Exercises
Exercise 2.2.1: For Loops with Range
Exercise 2.2.2: Loop with Enumerate
11.10.3 Part 3: Functions
Function Definition Exercises
Exercise 3.1.1: Basic Functions
Exercise 3.1.2: Functions with Default Parameters
Return Value Exercises
Exercise 3.2.1: Multiple Return Values
Exercise 3.2.2: Conditional Returns
11.10.4 Part 4: String Operations
String Formatting Exercises
Exercise 4.2.1: F-String Formatting
Exercise 4.2.2: String Methods
11.10.5 Part 5: Exception Handling
Try-Except Exercises
Exercise 5.1.1: Handling Multiple Exceptions
Exercise 5.1.2: Input Validation
11.10.6 Part 6: Debugging
Debugging Exercises
Exercise 6.1.1: Finding and Fixing Bugs
Here’s buggy code - find and fix the errors:
def calculate_average(numbers):
total = 0
for num in numbers: # FIXED: Added colon
total = total + num
return total / len(numbers)Should calculate average of [10, 20, 30] = 20 Find the bug(s) and fix them
Exercise 6.1.2: Using Assertions
11.10.7 Part 7: Object-Oriented Programming
Class Exercises
Exercise 7.1.1: Creating a Simple Class
Exercise 7.1.2: Classes with State Management
11.11 Summary of Key Concepts
After completing this appendix, you should understand:
- Data Structures: How to create and manipulate lists, tuples, dictionaries, and sets
- Control Flow: How to make decisions with if/elif/else and repeat code with loops
- Functions: How to write reusable code with parameters and return values
- Strings: How to create, manipulate, and format text output
- Error Handling: How to gracefully handle errors with try/except
- Debugging: How to find and fix bugs in your code
- OOP Basics: How to organize data and functions into classes
- Imports: How to use code from modules and libraries
These fundamentals provide the foundation for the code in Chapters 1-6, where you’ll apply these concepts to scientific computing with NumPy, image processing, and data analysis.