Administrative Logistics & Announcements
- Course Content & Announcements Correction:
- Some course announcements from the previous spring term were copied over without updated dates.
- Specific dates in previous announcements were mismatched (e.g., deleted entries marked with incorrect dates).
- Clarification emails will be sent out for future schedule corrections to avoid confusion regarding class times.
- Direct email communication with the instructor should be used for quick clarification on course scheduling.
- Lab Assignments Schedule:
- There are currently no graded lab assignments assigned.
- Lab 1: Lab 1 (originally scheduled for the prior week) will be covered synchronously during the lab session.
- Lab 1 Content: Focuses on foundational, simple Python operations and environment setup.
Python Strings & Collection Basics
- Overview of Strings as Data Collections:
- A string is an immutable collection of characters, including letters, digits, symbols, whitespace, and punctuation marks.
- String literals can be enclosed in either single quotation marks (
'...') or double quotation marks ("..."). - Syntax Rule: Quotation mark usage must be consistent. A string starting with a single quote must end with a single quote, and a string starting with a double quote must end with a double quote.
- String Operations:
- Concatenation: Strings are joined together into a single new string using the addition operator (
+). - Indexing: Individual characters within a string are accessed using zero-based indexing inside square brackets (
[]).- Example: For the string
"hello world", accessing index 0 yields 'H' (or 'h').
- Length Determination: The
len() function returns the total count of all characters, including visible characters and spaces.- Detailed Calculation Example: Consider the string
"this is a string":- Visible characters:
this (4) + is (2) + a (1) + string (6) = 13 characters. - Whitespace characters: 3 blank spaces.
- Total String Length: 13+3=16
- Memory Structure: Python strings are self-contained collections. Unlike low-level languages such as C++ or Java, Python strings do not use explicit null-terminator characters (e.g.,
\0) or end-of-line stoppage characters to signify string termination.
- Formatted String Literals (f-strings):
- An f-string is denoted by prefixing the string literal with an
f or F (e.g., f"..."). - Curly braces (
{}) define replaceable placeholder expressions inside the string. Expressions inside curly braces can include variables, mathematical calculations, or function calls. - Syntax Comparison: Modern Python prefers f-strings over the older
.format() method due to superior readability, concise syntax, and convenience. - Example 1 (Variable Substitution):
- Variable:
name = "Reiko" - Formatted String:
f"she said her name is {name}" - Output:
"she said her name is Reiko"
- Example 2 (Function Evaluation):
- Formatted String:
f"{name} is {len(name)}" - Evaluation:
{name} evaluates to "Reiko", and {len(name)} evaluates to standard numerical length 5. - Output:
"Reiko is 5"
- User Input via
input() Function:- The
input() function prompts the user for standard input from the console. - Syntax:
input(prompt_string) - Execution Flow: Displays the prompt string, pauses execution to present a text box/entry line, and waits for the user to type a response and press
Enter. - Type Casting Rule: The
input() function always returns the user's entry as a string (str), regardless of what characters or numbers are entered.- Example: Entering numerical digits like
505 into username = input("What's your name?") yields username = "505", where type(username) evaluates to <class 'str'>.
- Manual Numeric Conversion: To use input values in arithmetic operations, the returned string must be explicitly cast using
int() or float().- Code Sequence:
```python
username = input("What's your name?") # User inputs: 505
number = int(username) # Explicitly cast to integer
# type(number) now evaluates to
# Console Output & Escape Characters
* **Standard Output with `print()`**:
* Accepts single items, formatted strings, or multiple comma-separated arguments.
* Comma-separated items in a `print()` call are output sequentially, separated by a default single space. The commas themselves are not printed.
* **Keyword Argument: `end`**:
* By default, `print()` appends a newline character (`\n`) at the end of its output.
* The `end` parameter overrides this default ending character with custom strings or symbols.
* *Example*: Formatting percentages directly:
```python
n = 5 * (1 / 100) # Numerical calculation yielding percentage
print(5, end="%") # Outputs: 5%
- Quotes and Escape Characters:
- Enclosing double quotes directly inside a double-quoted string literal causes a syntax error because Python interprets the second double quote as the string delimiter.
- Solution 1 (Quote Alternation): Enclose the string in single quotes if double quotes are needed inside, e.g.,
'My name is "James"'. - Solution 2 (Backslash Escaping): Prefix inner double quotes with a backslash (
\"), e.g., "My name is \"James\"". - Common Escape Sequences:
\": Literal double quotation mark.\': Literal single quotation mark.\\: Literal backslash.\n: Linefeed / New line.\t: Horizontal tab.
Control Flow: Branching Statements
if-elif-else Structure:- Provides conditional branching based on logical comparisons and boolean expressions.
- Execution Logic:
- Evaluates the initial
if statement condition. - If
True, executes the indented code block (indented one standard unit to the right) and skips all remaining branches. - If
False, sequentially evaluates subsequent elif (else if) conditions. - If all prior conditions evaluate to
False, the else block executes.
- Flexibility:
elif and else blocks are optional. Multiple elif blocks can be chained together.
- Pattern Matching with
match-case:- Introduced for structural pattern matching, structurally optimized for discrete string and object matching (analogous to
switch-case in other programming languages). - Distinction:
if-else is primary for complex logical evaluation and mathematical comparisons, whereas match-case provides cleaner syntax for direct structural and literal string matching. - Wildcard Case (
case _): Acts as the default fallback branch, equivalent to the else block in an if-else chain. - Syntax & Advanced Pattern Matching Example:
```python
command = "run"
match command:
case "run":
print("Executing run command")
case "speak" | "say hi": # Logical OR within string matching
print("The robot says hi")
case _ if command.isdigit(): # Conditional guard using string methods
print("Numeric command processed")
case _: # Wildcard default match
print("Unknown command")
* **String Methods used in Guards**: `.isdigit()`, `.isalpha()`, `.isidentifier()`.
# Control Flow: Iterative Loops (`for` and `while`)
* **Fundamental Loop Concepts**:
* Iteration executes a block of code multiple times.
* *Historical Context*: Primitive programming languages (e.g., early Pascal variations) lacked structured high-level loop constructs, relying instead on explicit jump statements to return to instructions.
* **`for` Loops**:
* **Fixed Numerical Iterations with `range()`**:
* `range(stop)`: Generates integers from 0 up to stop−1.
* *Example*: `range(4)` generates sequence `0, 1, 2, 3` (executes exactly 4 times).
* `range(start, stop)`: Generates integers from start up to stop−1.
* *Example*: `range(4, 8)` generates sequence `4, 5, 6, 7` (executes 4 times).
* `range(start, stop, step)`: Generates integers from start up to stop−1, incrementing by step.
* *Example*: `range(4, 20, 2)` generates sequence `4, 6, 8, 10, 12, 14, 16, 18`.
* **Direct Iteration over Collections**:
* Loops directly over items in lists, tuples, sets, or dictionaries.
* *Example*: `for animal in animals:` assigns each item sequentially to `animal`.
* **Indexed Iteration with `enumerate()`**:
* Generates paired tuples containing an incremental index counter and the collection item.
* *Pythonic Pattern*: `for i, value in enumerate(animals):` allows simultaneous access to index `i` (for `animals[i]`) and item `value`.
* **Loop Variable Persistence**: The iteration counter variable in a Python `for` loop retains its final assigned value in the enclosing scope after the loop terminates.
* *Example*: Printing variable `i` outside a completed `for i in range(4, 20, 2):` loop outputs `18`.
* **`while` Loops**:
* Executes repeatedly as long as a specified boolean condition remains `True`.
* Used when the precise number of required iterations is unknown beforehand.
* **Infinite Loop Risk**: The loop condition state variable **must** be updated within the loop body. If the variable is not updated, the loop will run indefinitely.
* *Example*:
```python
x = 0
while x < 4:
print(x)
x += 1 # State modification prevents infinite execution
Functions, Data Types, & Type Hinting
- Function Definitions:
- Defined using the
def keyword, followed by the function name, parameter list in parentheses, and a colon (:). - The function body must be indented to the right.
- Functions execute only when explicitly invoked.
- Function Invocations & Arguments:
- Positional Arguments: Parameters are assigned based on the order passed in the call (e.g.,
add(5, 6) passes 5 to the first parameter and 6 to the second). - Keyword Arguments: Parameters are assigned by explicitly naming them in the call (e.g.,
add(y=6, x=5)). Order does not matter when keywords are specified.
- Operator Overloading with
+:- If both operands are integers (
int + int), + performs arithmetic addition (5+6=11). - If both operands are strings (
str + str), + performs string concatenation ("5" + "6" = "56"). - If operands are mixed types (e.g.,
int + str), Python raises a TypeError (unsupported operand type(s) for +).
- Function Type Hinting:
- Type hints document intended argument data types and return types.
- Syntax:
def add_numbers(a: int, b: int) -> int:a: int indicates parameter a is expected to be an integer.-> int indicates the return value is expected to be an integer.
- Non-Enforcement Rule: Type hints in Python are purely for code readability, documentation, and static analysis tools. They do not strictly enforce data types at runtime. Passing incompatible types (e.g., strings to integer-hinted parameters) will not be blocked by the interpreter until an incompatible operation is executed.
Exception & Error Handling (try-except-else-finally)
- Purpose: Prevents program execution from crashing when runtime errors or invalid operations occur.
- Structure & Execution Flow:
try: Encloses code that might potentially throw/raise an exception.except: Triggers when an error occurs inside the try block. Can intercept specific built-in exception types (e.g., except IndexError as e:, except TypeError:, except ZeroDivisionError:).else: Executes only if the try block completed successfully without raising any exceptions.finally: Executes always, regardless of whether an exception occurred, was caught, or was avoided. Ideal for resource cleanup.raise: Explicitly raises a specific runtime error intentionally (e.g., raise RuntimeError).
- Comprehensive Exception Handling Example:
```python
try:
# Attempting to access an out-of-bounds index on a 2-element list
element = my_list[4]
except IndexError as e:
print("Warning: Index out of bound")
except (TypeError, NameError):
pass # 'pass' acts as a silent placeholder block
else:
print("Execution successful: All good")
finally:
print("Program execution complete")
# Variable Scope: Global, Local, and Nonlocal
* **Global Scope**:
* Variables declared at the outermost, left-most indentation level exist in the global scope.
* Global variables are readable throughout the module, but modifying a global variable inside a local function scope requires explicit declaration.
* **Local Scope**:
* Variables declared inside a function body belong to that function's local scope.
* Assigning a value to a variable inside a function creates a new local variable by default, leaving any identically named global variable untouched.
* **`global` Keyword**:
* Used within a local scope to declare that operations on a variable target the outer global instance.
* *Trace Example*:
```python
x = 5 # Global variable x
def set_x(num):
x = num # Creates a LOCAL variable x; global x remains 5
def set_global_x(num):
global x # Binds local reference to global x
x = num # Updates global x to 96
nonlocal Keyword:- Used specifically inside nested functions (functions defined inside other functions).
- Binds a variable to the nearest outer (enclosing) non-global function scope.
- Constraint:
nonlocal cannot bind directly to global scope variables. Attempting to use nonlocal on a variable that exists only in the global scope causes a syntax binding error (nonlocal x is non-binding). - Trace Example:
```python
def outer_function():
x = 43 # Outer local variable
def nested_function():
nonlocal x # Binds to outer_function's x
x = 9666 # Modifies outer_function's x to 9666
nested_function()
print(x) # Prints 9666
# Advanced Arguments: `*args` and `**kwargs`
* **Dynamic Argument Passing**:
* Used when a function needs to accept an arbitrary, unknown number of input parameters.
* **Single Asterisk (`*args`)**:
* Pointers to positional argument lists.
* Packs arbitrary positional arguments into a single **tuple**.
* **Double Asterisk (`**kwargs`)**:
* Pointers to keyword argument pairs.
* Packs arbitrary keyword arguments into a single **dictionary**.
* **Syntax Definition**:
```python
def execute_all(*args, **kwargs):
print(args) # Outputs tuple of positional arguments
print(kwargs) # Outputs dictionary of keyword arguments
- Practical Application (Geometric Area Calculation):
- A single generic shape function can inspect
len(args) to apply different formulas dynamically:- 1 Parameter (side): Computes square area: Area=side2
- 2 Parameters (base,height): Computes triangle area: Area=21×base×height or rectangle area: Area=width×height
Functional Programming Hacks & Comprehensions
- Lambda Functions:
- Inline, anonymous single-line functions.
- Syntax:
lambda param1, param2: expression - Example:
add = lambda x, y: x + y replaces explicit def definitions for simple one-line calculations.
- Built-in Functional Tools:
map(function, iterable, ...):- Applies a function to every item in an iterable and returns a modified iterator.
- Type Conversion Example:
map(float, [1, 2, 3]) converts items to floating point values [1.0, 2.0, 3.0]. - Multi-Iterable Element-Wise Comparison:
list(map(max, [1, 2, 3], [4, 2, 1])) evaluates pairwise maximums to return [4, 2, 3].
filter(function, iterable):- Applies a predicate boolean function to each element, retaining only elements where the function returns
True. - Example:
list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) evaluates 3, 4, 5 as False and 6, 7 as True, returning [6, 7].
zip(*iterables) Function:- Pairs elements from multiple collections positional index by index, returning an iterator of tuples.
- Example:
zip(["apple", "banana", "cherry"], [2, 5, 12]) produces [("apple", 2), ("banana", 5), ("cherry", 12)]. - Unequal Length Behavior: Truncates automatically to match the length of the shortest input iterable; trailing elements of longer iterables are discarded.
- Comprehensions:
- Provides high-performance, concise syntax for creating collections (faster execution than traditional
for loop population). - List Comprehension:
- Syntax:
[x for x in sequence if condition] - Example:
[x for x in [3, 4, 5, 6, 7] if x > 5] yields [6, 7].
- Set Comprehension:
- Syntax:
{x for x in sequence if condition} - Example:
{x for x in "abcdef" if x not in "abc"} filters out characters 'a', 'b', and 'c', automatically removing duplicate entries to yield set {'d', 'e', 'f'}.
- Dictionary Comprehension:
- Syntax:
{key_expr: value_expr for item in sequence} - Example:
{x: x**2 for x in range(5)} generates key-value pairs mapping integers to their squares: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}.
Lecture Discussion & Student Q&A
- Formatting Notations:
- Student Question: Does the
f prefix in f-strings function as a print call? - Response: No. The
f prefix is a string literal notation marking the string as formatted. Printing requires wrapping the f-string inside print(), e.g., print(f"...").
- Pattern Matching Fall-Through:
- Student Question: In
match-case blocks, does execution fall through to check subsequent cases after finding a match? - Response: No. Execution evaluates sequentially from top to bottom. Once a case match is found, Python executes that case block and exits the entire
match-case construct entirely.
- String Operands in Generic Add Functions:
- Student Question: What happens if two string arguments (e.g.,
"5" and "6") are passed into a basic addition function returning x + y? - Response: The function returns string concatenation (
"56"), because the + operator joins string operands.