{ "cells": [ { "cell_type": "markdown", "id": "3f23aabc", "metadata": {}, "source": [ "# Lesson 1: Control Structures\n" ] }, { "cell_type": "markdown", "id": "bff33a04", "metadata": {}, "source": [ "\n", "## Objectives\n", "\n", "In this lesson, we will introduce fundamental control structures for Python. By the end of this lesson, students will be able to:\n", "\n", "1. Evaluate expressions involving arithmetic and boolean operators.\n", "2. Apply `for` loops to iterate over a range of numbers increasing/decreasing by a fixed step size.\n", "3. Apply `while` loops to iterate until reaching a desired program condition." ] }, { "cell_type": "markdown", "id": "82871fca", "metadata": {}, "source": [ "In this class, we will use a combination of **Jupyter notebooks** and **Python scripts** for lessons and coding practice.\n", "\n", "In a Jupyter notebook, you will find a combination of text-based **Markdown cells** and runnable Python snippets, which we call **code cells**. To edit a Markdown cell, double-click the text to edit it. Then, use the keyboard shortcut **Ctrl + Enter** to apply your changes. This is a great way to take notes on the course content, if you wish.\n", "\n", "You can find a list of Markdown formatting tips [here](https://www.markdownguide.org/cheat-sheet/)!" ] }, { "cell_type": "markdown", "id": "6d2b1c72", "metadata": {}, "source": [ "## Python Basics\n", "\n", "### Printing\n", "\n", "Printing looks a bit different in Python than in other languages. To print any text, we will use the `print` function." ] }, { "cell_type": "code", "execution_count": null, "id": "0c11592a", "metadata": {}, "outputs": [], "source": [ "print(\"Hello, world!\")" ] }, { "cell_type": "markdown", "id": "3352e2fc", "metadata": {}, "source": [ "Try changing \"world\" to your name, or to the name of a friend!\n", "\n", "One thing that Python is really good at is providing slightly different ways of using the same syntax to do helpful things. For example, you can also pass multiple values to the `print` function and it adds spaces between them!" ] }, { "cell_type": "code", "execution_count": null, "id": "243fae6c", "metadata": {}, "outputs": [], "source": [ "print('Hello', 'world', '!')" ] }, { "cell_type": "markdown", "id": "b808a848", "metadata": {}, "source": [ "**Quotation Marks**\n", "It generally doesn't matter whether you use single quotes (`''`) or double quotes (`\"\"`) for print statements. However, if the string you're trying to print uses one type of quotation mark, use the other to indicate the string itself! Example: `'Say \"what?\"'` or `\"What's that?\"`" ] }, { "cell_type": "markdown", "id": "975674e8", "metadata": {}, "source": [ "### Main-method pattern\n", "\n", "A **Python program** is a series of statements that are executed from top to bottom. We will learn lots of different statements in this course!\n", "\n", "In CSE 163, we will ask you to put a little bit of starter code in every Python script you write. We call this the **main-method pattern**. We can't really motivate why you need to use this quite yet; you'll have to trust us that it is the right thing to do. We introduce this pattern now to get you in the practice of writing from the onset of your Python journey. We will come back in future weeks and actually dive into what this pattern does and why it's necessary.\n", "\n", "Recall that we could write a Python program in a code cell to print \"Hello world\" like the following:" ] }, { "cell_type": "code", "execution_count": null, "id": "6dc62968", "metadata": {}, "outputs": [], "source": [ "print(\"Hello, world!\")" ] }, { "cell_type": "markdown", "id": "808e21e1", "metadata": {}, "source": [ "Note that if you tried to run this in a Python script or a code cell of a Jupyter notebook, this will run either way. However, instead, we will commonly ask you to write a few extra lines of code \"around\" the program you wanted to write as the following." ] }, { "cell_type": "code", "execution_count": 1, "id": "acde4a35", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world!\n" ] } ], "source": [ "def main():\n", " # Put your code, indented inside here\n", " print('Hello world!')\n", " \n", " \n", "if __name__ == '__main__':\n", " main()" ] }, { "cell_type": "markdown", "id": "dfe0b989", "metadata": {}, "source": [ "(Note the comment in the second line, which is prefaced by a `#`!)\n", "\n", "We'll start you off by providing the main-method pattern as starter code for lessons and practice, but you will get used to writing these weird symbols by yourself! Again, we promise to explain this later, we just don't have everything we need for that explanation right now!\n", "\n", "> For individual code snippets on the course website and in Jupyter notebooks, the main-method pattern will be omitted. It is not needed for the Jupyter notebook, and we omit it from lessons to keep things more readable. **For any Python script that you write in this class, including for take-home assessments, you will always need to use the main-method pattern for these files.**" ] }, { "cell_type": "markdown", "id": "fad1cc8b", "metadata": {}, "source": [ "### Variables\n", "\n", "Variables store values. Each Python value is composed of a value and its type. Unlike Java and older languages like C, Python doesn't require you to define the type of a variable. A variable's **type** is determined by the **value** it references. Additionally, throughout the lifetime of the program running, the variable can be made to hold a new value of a different type using an **assignment statement**.\n", "\n", "The following snippet creates a variable named `x` that stores the value `3` of type `int` (for integer) and a variable named `y` that stores the value `4.2` of type `float` (for floating-point number). One line 3, it then re-assigned `x` to store the value `3.7` of type `float`. This is why the program prints `x = 3.7` and `y = 4.2`." ] }, { "cell_type": "code", "execution_count": 2, "id": "6615bc61", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = 3.7\n", "y = 4.2\n" ] } ], "source": [ "x = 3\n", "y = 4.2\n", "x = 3.7\n", "\n", "print('x =', x)\n", "print('y =', y)" ] }, { "cell_type": "markdown", "id": "ef606a72", "metadata": {}, "source": [ "In a Jupyter notebook, you can display the output by writing the variable name in a code cell and evaluating that code cell." ] }, { "cell_type": "code", "execution_count": 3, "id": "fccb9681", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.7" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "markdown", "id": "de63c5bf", "metadata": {}, "source": [ "### Expressions\n", "\n", "Python supports many operations for built-in types. Specifically, here are the operations defined for numeric types like `int` and `float`.\n", "\n", "* Addition: `a + b`\n", "* Subtraction: `a - b`\n", "* Multiplication: `a * b`\n", "* Division: `a / b` (e.g., 7 / 3 == 2.333333333)\n", "* Integer division: `a // b` (e.g., 7 // 3 == 2)\n", "* Mod: `a % b` (i.e., leftover from integer division as in 7 % 3 == 1)\n", "* Exponentiation: `a ** b` (i.e., $a^b$)\n", "\n", "You can also nest expressions (and use parentheses to define order) since all expressions evaluate to some value." ] }, { "cell_type": "code", "execution_count": null, "id": "6fad88a1", "metadata": {}, "outputs": [], "source": [ "a = 3\n", "print(a - (2 * a) + (a ** (1 + 2)))" ] }, { "cell_type": "markdown", "id": "f974a799", "metadata": {}, "source": [ "What do you think is the output of this print statement?" ] }, { "cell_type": "markdown", "id": "f2a43159", "metadata": {}, "source": [ "## Types and booleans\n", "\n", "In addition to string and numeric types, Python also has a `bool` type (equivalent to Java's `boolean`) that only takes on the values `True` or `False`.\n", "\n", "Just like any other value, a `bool` can be stored in variables:" ] }, { "cell_type": "code", "execution_count": null, "id": "a3de9ce4", "metadata": {}, "outputs": [], "source": [ "b1 = True\n", "b2 = False\n", "print(b1, b2)" ] }, { "cell_type": "markdown", "id": "95955f82", "metadata": {}, "source": [ "They have operations:\n", "\n", "* `a and b`: `True` if and only if both values are `True`\n", "* `a or b`: `True` if either or both values are `True`\n", "* `not a`: \"flips\" to the opposite boolean value\n", "\n", "And they can be created by doing comparisons between other values. Just like how you can create a new numeric value from evaluating arithmetic operations, you can create a `bool` value by using **logical operations**." ] }, { "cell_type": "code", "execution_count": null, "id": "45b4fbd0", "metadata": {}, "outputs": [], "source": [ "x = 3\n", "print(x < 4) # \"Is x is less than 4?\"\n", "print(x >= 5) # \"Is x greater than or equal to 5?\"\n", "print(x == 2) # \"Is x equal to 2?\"\n", "print(x != 2) # \"Is x not equal to 2?\"" ] }, { "cell_type": "markdown", "id": "cbde3d42", "metadata": {}, "source": [ "## While loops\n", "\n", "If you want to repeat some computation, a programming language usually provides a construct called a **loop** that lets you repeat code some number of times. \n", "\n", "A **`while` loop** has a **condition** and a **body**. The while loop proceeds in iterations, each iteration executes the **body** only if the **condition** is `True`, otherwise the loop ends. In general, a `while` loop looks like:\n", "\n", "```python\n", "while condition:\n", " # Loop body\n", " statement\n", " statement\n", " statement\n", "```" ] }, { "cell_type": "markdown", "id": "58e33687", "metadata": {}, "source": [ "Note the indentation and the colon at the end of the condition! Pythonic syntax is sensitive to whitespace, so in order to make sure the body is properly defined, it needs to be **indented** under the condition.\n", "\n", "As an example, let's take a look at this `while` loop:" ] }, { "cell_type": "code", "execution_count": null, "id": "1c735105", "metadata": {}, "outputs": [], "source": [ "x = 1\n", "while x < 100:\n", " print(x)\n", " x = x * 2\n", "\n", "print('After loop', x)" ] }, { "cell_type": "markdown", "id": "8885d468", "metadata": {}, "source": [ "The condition here is `x < 100`, so the loop keeps executing the body (`print(x)` and `x = x * 2`) until the next iteration it is `False` (when `x = 128`). After the loop ends, it continues on to the code after the loop: `print('After loop', x)`.\n", "\n", "**Food for thought:** What happens if you indent that final print statement?" ] }, { "cell_type": "markdown", "id": "839e7123", "metadata": {}, "source": [ "## For loops\n", "\n", "Another type of loop that you'll commonly see in Python is the `for` loop. The `for` loop has a **body** that runs for each item in a **sequence** and uses a **loop variable** to keep track of the current item. \n", "\n", "We'll start by showing an example and then explain the parts." ] }, { "cell_type": "code", "execution_count": null, "id": "f5da7739", "metadata": {}, "outputs": [], "source": [ "for i in range(5):\n", " print('Loop', i)" ] }, { "cell_type": "markdown", "id": "1d56a309", "metadata": {}, "source": [ "The `for` loop has the following components\n", "\n", "* `range(5)` describes the **sequence** of values we want to use. In this case, `range(5)` means the values `0, 1, 2, 3, 4.` We will explain `range` in the next section.\n", "* `i` is the **loop variable** that can be used in the body. On the first iteration, `i = 0`; then `i = 1` on the next; and so on until the last iteration, where `i = 4`.\n", "* `print('Loop', i)` is the body.\n", "\n", "The `for` loop operates very similarly to the `while` loop, but the key difference is it will loop over the sequence of values specified after the in keyword. Just like the while loop, you put a : at the end of the line containing the keyword for and the body is indented inside the loop." ] }, { "cell_type": "markdown", "id": "abf8862f", "metadata": {}, "source": [ "### `range` Function\n", "\n", "`range` is a function in Python provided to make it easy to make sequences of numbers in a range. It turns out, there are three different ways to call `range` that let you do slightly different types of loops!" ] }, { "cell_type": "code", "execution_count": null, "id": "b4151f2b", "metadata": {}, "outputs": [], "source": [ "# From 0 (inclusive) to A (exclusive)\n", "for i in range(10):\n", " print('Loop', i)" ] }, { "cell_type": "code", "execution_count": null, "id": "1961b1c5", "metadata": {}, "outputs": [], "source": [ "# From A (inclusive) to B (exclusive)\n", "for i in range(2, 10):\n", " print('Loop', i)" ] }, { "cell_type": "code", "execution_count": null, "id": "566b9f18", "metadata": {}, "outputs": [], "source": [ "# From A (inclusive) to B (exclusive) using step size C\n", "for i in range(2, 10, 3):\n", " print('Loop', i)" ] }, { "cell_type": "markdown", "id": "4607ac27", "metadata": {}, "source": [ "**Food for thought:** What do you think would happen if any of these values were negative?" ] }, { "cell_type": "markdown", "id": "44f3ce8f", "metadata": {}, "source": [ "## Conditionals\n", "\n", "**Conditional statements** let you execute code conditionally based on some condition; they are similar in nature to the `while` loop but only run at most once. \n", "\n", "In Python, the keywords to control these conditionals are `if`, `elif` (read as \"else if\"), and `else`.\n", "\n", "A conditional block is an `if` block optionally followed by any number of `elif` blocks optionally followed by at most one `else` block. Let's look at an example:" ] }, { "cell_type": "code", "execution_count": null, "id": "f1f858be", "metadata": {}, "outputs": [], "source": [ "x = 14\n", "if x < 10:\n", " print('A')\n", "elif x >= 13:\n", " print('B')\n", "elif x >= 20:\n", " print('Not possible')\n", "else:\n", " print('C')" ] }, { "cell_type": "markdown", "id": "a9fe3dee", "metadata": {}, "source": [ "Let's follow along to see what is printed:\n", "\n", "* We define `x = 14`.\n", "* Check if `x < 10`. Since 14 is not less than 10, we skip the body of this conditional statement and move on to the next.\n", "* Check if `x >= 13`. Since 14 is greater than 13, we move into the body of this conditional statement, which says that we should `print('B')`\n", "* We are done!\n", "\n", "**Food for thought:** Why is it impossible to enter the `elif x >= 20` statement? What could we do instead to print the string `'Not possible'`?" ] }, { "cell_type": "markdown", "id": "d82fb58c", "metadata": {}, "source": [ "## Functions\n", "\n", "A **function** is a named procedure with a series of instructions that can be **called** in your program to execute those instructions.\n", "\n", "To call a function, use its name and use () after it to make it a call For example, `print` is actually a function defined by Python, so a \"print statement\" is really just calling this `print` function.\n", "\n", "As we saw earlier, we can pass **parameters** to this function call to give it inputs. For example, the `print` function takes parameters for the things to print." ] }, { "cell_type": "code", "execution_count": null, "id": "e4c94518", "metadata": {}, "outputs": [], "source": [ "print(\"To be or not to be\")" ] }, { "cell_type": "markdown", "id": "880e346f", "metadata": {}, "source": [ "Functions defined by Python are called **built-in functions**. `print` and `range` are two examples of built-in functions. Some functions can also **return** values, making them available for use outside the function.\n", "\n", "If you want to define a function that takes parameters, you put variable names in between the `()` for each parameter you want the function to take. If you want the function to return a value, you use a `return` statement like the example below. To call the function, you need to actually use a function call! (Make sure that it's not indented under your function header!)" ] }, { "cell_type": "code", "execution_count": null, "id": "8bd379ca", "metadata": {}, "outputs": [], "source": [ "def mean(a, b):\n", " print('Calling mean with', a, b)\n", " return (a + b) / 2\n", "\n", "mean(1, 2) # Have to call it passing in two parameters!" ] }, { "cell_type": "markdown", "id": "e20a533a", "metadata": {}, "source": [ "## ⏸️ Pause and 🧠 Think\n", "\n", "Take a moment to review the following concepts and reflect on your own understanding. A good temperature check for your understanding is asking yourself whether you might be able to explain these concepts to a friend outside of this class.\n", "\n", "Here's what we covered in this lesson:\n", "* `print` statements\n", "* Variables and variable assignment\n", "* Variable types (strings, `float`, `int`, `bool`)\n", "* Arithmetic operators (`+`, `-`, `/`, `*`, `//`, `%`, `**`)\n", "* Logical operators (`and`, `or`, `not`, `<`, `>`, `<=` `>=`, `==`, `!=`)\n", "* `while` loops\n", "* `for` loops\n", "* `range`\n", "* Conditionals\n", "* Functions\n", "\n", "Here are some other guiding exercises and questions to help you reflect on what you've seen so far:\n", "\n", "1. In your own words, write a few sentences summarizing what you learned in this lesson.\n", "2. What did you find challenging in this lesson? Come up with some questions you might ask your peers or the course staff to help you better understand that concept.\n", "3. What was familiar about what you saw in this lesson? How might you relate it to things you have learned before?\n", "4. Throughout the lesson, there were a few **Food for thought** questions. Try exploring one or more of them and see what you find." ] }, { "cell_type": "markdown", "id": "eee247b4", "metadata": {}, "source": [ "## In-Class\n", "\n", "When you come to class, we will work together on evaluating Pythonic expressions, and completing `countdown.py` and `fibonacci.py`. Make sure that you have a way of editing and running these files!" ] }, { "cell_type": "markdown", "id": "ed1b7b2f", "metadata": {}, "source": [ "### Expressions\n", "\n", "1. What is the output of the following expression?" ] }, { "cell_type": "code", "execution_count": null, "id": "c5d516c8", "metadata": {}, "outputs": [], "source": [ "x = 2.4\n", "y = 1.2\n", "x = x / y\n", "y = 5\n", "\n", "print(x ** 2 <= y)" ] }, { "cell_type": "markdown", "id": "c4d23146", "metadata": {}, "source": [ "2. What is the output of the following expression?" ] }, { "cell_type": "code", "execution_count": null, "id": "24bfa576", "metadata": {}, "outputs": [], "source": [ "a = 3\n", "b = 1\n", "\n", "while (a % 2 != 0):\n", " b += 1\n", " a += a ** b\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "id": "dce97754", "metadata": {}, "source": [ "### Countdown\n", "\n", "For this practice problem, refer to `countdown.py`.\n", "\n", "First, let's write a program in `main` that counts down from one minute decrementing by 10 seconds. Use a `for` loop. The output of the program should be the following:\n", "\n", "```\n", "One minute countdown\n", "60\n", "50\n", "40\n", "30\n", "20\n", "10\n", "0\n", "Done!\n", "```\n", "\n", "The lines of numbers should all be produced by your `for` loop while the first and last lines will appear outside the loop since they only happen once. Think carefully about the inputs to `range`—the arguments can be negative!\n", "\n", "Once you've written this program in `main`, let's reuse this logic in a function. We'll write the function `countdown` that takes a starting number of int seconds and starts the countdown from there instead (still decrementing by 10s).\n", "\n", "The format of the output will be slightly different to accommodate this starting point: if the sequence does not exactly count down to `0` (e.g., starting from `15`), then `0` will not be printed. If the starting number of seconds is less than 0, it should instead print `\"Start must be non-negative!\"`\n", "\n", "Here are four example calls to the function with their corresponding outputs. print statements are included for spacing between different calls to countdown.\n", "\n", "```python\n", "countdown(60)\n", "print()\n", "countdown(15)\n", "print()\n", "countdown(-4)\n", "print()\n", "countdown(0)\n", "```\n", "\n", "Output:\n", "```\n", "60 second countdown\n", "60\n", "50\n", "40\n", "30\n", "20\n", "10\n", "0\n", "Done!\n", "\n", "15 second countdown\n", "15\n", "5\n", "Done!\n", "\n", "Start must be non-negative!\n", "\n", "0 second countdown\n", "0\n", "Done!\n", "```" ] }, { "cell_type": "markdown", "id": "04411946", "metadata": {}, "source": [ "### Fibonacci\n", "\n", "For this practice problem, refer to `fibonacci.py`.\n", "\n", "The Fibonacci Sequence is the following sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ... The sequence starts with 1 and 1. The next number is the sum of the previous two.\n", "\n", "Here, we will write a function `fibonacci` to compute the first Fibonacci number larger than a given value `n`. As an example, if we call `fibonacci(0)`, then the output would be `1`, since `1` is the first Fibonacci number greater than 0.\n", "\n", "Our function should **return** the first Fibonacci number in the sequence that exceeds the given value `n`. Here are more examples of output, where the expected output is written as an in-line comment next to the `print` and function call:\n", "\n", "```python\n", "print(fibonacci(0)) # 1\n", "print(fibonacci(1)) # 2\n", "print(fibonacci(2)) # 3\n", "```\n", "\n", "**Hint:** Create two variables representing the `curr` and `prev` Fibonacci numbers. The next number is the sum of `curr` and `prev`." ] }, { "cell_type": "markdown", "id": "81e7a7fc", "metadata": {}, "source": [ "## Canvas Quiz\n", "All done with the lesson? Complete the [Canvas Quiz linked here!](https://canvas.uw.edu/courses/1860345/quizzes/2327096)" ] } ], "metadata": { "kernelspec": { "display_name": "cse163", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.5" } }, "nbformat": 4, "nbformat_minor": 5 }