{ "cells": [ { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-820ab9eec85e7818", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Conditional statements\n", "\n", "```{admonition} Interactive page\n", ":class: warning, dropdown\n", "This is an interactive book page. Press launch button at the top right side.\n", "```" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-820ab9eec85e7818", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## If statement\n", "\n", "You may remember that we've already seen an example of an `if` statement in a [previous chapter](../chapter4/data-types.ipynb). The syntax of the `if` statement is as follows: \n", "\n", "```\n", "if expression:\n", " code block to be executed if the expression is True\n", "```\n", "\n", "Here, `expression` is a piece of code the evaluates to either the value `True` or `False`. \n", "Note that the **code block must be indented** - that tells Python which code is inside the `if` and which is not.\n", "\n", "Here are a few simple examples:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "tags": [ "remove-output" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True is true\n" ] } ], "source": [ "if True:\n", " print(\"True is true\") " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if True:\n", " print(\"The code block\")\n", " print(\"after 'if' statements\")\n", " print(\"can have multiple lines.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if False:\n", " print(\"False is not True (this will not be printed)\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if not False:\n", " print(\"not False is True\") " ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-8f5002353d747ef9", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "```{exercise}\n", ":class: dropdown\n", "Try the following conditional statement by filling in the placeholder `---` by:\n", "1. integer `1`\n", "2. float `5.4`\n", "3. integer `-1`\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if ---:\n", " print('The expression is true')" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-06bb622a4a2db31e", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "```{exercise}\n", ":class: dropdown\n", "Check if the conditional statement works with the variables by filling the placeholder `---` by:\n", "1. Boolean variable (`a = True`)\n", "2. numerical variable (`a = -10.54`)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = ---\n", "if a:\n", " print('The expression is true')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "thebe-remove-input-init" ] }, "outputs": [], "source": [ "import micropip\n", "await micropip.install(\"jupyterquiz\")\n", "from jupyterquiz import display_quiz\n", "import json\n", "\n", "with open(\"questions3.json\", \"r\") as file:\n", " questions=json.load(file)\n", " \n", "display_quiz(questions, border_radius=0)" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-ad422752c90b5a9e", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Comparison and test operators\n", "\n", "In all the examples above, the `expression` in the `if` statement was always a value that is either `True` or `False` (except for the example of `not False`). \n", "More generally, however, the `expression` **can also include comparisons**. Some examples of numerical comparisons are given here:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if 5 == 5:\n", " print(\"A double equal sign '==' compares the two sides of itself and gives the\")\n", " print(\"result 'True' if the two sides have the same value\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a == 5:\n", " print(\"== also works with variables\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if 5 == a:\n", " print(\"The variable can be on either side\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "b = 5\n", "if a == b:\n", " print(\"and == also works with two variables\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a = 5:\n", " print(\"This will give an error! A single = is an assignment operator, not a conditional test\")\n", " print(\"To check if a is equal to 5, you need to use the double equal sign ==\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{warning}\n", "Remember the difference between `=` (assignment operator) and `==` (equality operator) in Python.\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a == 6:\n", " print(\"This will not be printed because condition is False.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if 2*a == 10:\n", " print(\"You can also use mathematical expressions\") " ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-2c4696ee3922ab23", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "In addition to the equality operator `==`, there are also several other comparison operators such as `<`, `>`, `>=`, `<=`, `!=`.\n", "\n", "```{exercise}\n", ":class: dropdown\n", "Test the operators `<`, `>`, `>=`, `<=`, `!=` by trying them in an `if` statement with numerical values. The first example is given in the code cell below. \n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if 5 < 10:\n", " print('The expression is true')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Python conditional operators\n", ":class: important\n", "`==` equal \\\n", "`!=` not equal \\\n", "`<` less than \\\n", "`<=` less than or equal to \\\n", "`>` greater than \\\n", "`>=` greater than or equal to\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "thebe-remove-input-init" ] }, "outputs": [], "source": [ "import micropip\n", "await micropip.install(\"jupyterquiz\")\n", "from jupyterquiz import display_quiz\n", "import json\n", "\n", "with open(\"questions4.json\", \"r\") as file:\n", " questions=json.load(file)\n", " \n", "display_quiz(questions, border_radius=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ways to generate True/False\n", "\n", "Boolean True/False may also be given by some other things:\n", "\n", "* **Non-Boolean variables** can themselves be interpreted as Booleans. \\\n", "As we've seen above, numerics (`float`, `int`) are interpreted as `False` if they are equal to 0.\n", "Lists, tuples, dictionaries, and strings are interpreted as `False` if they are empty (with nothing inside).\n", "`None` (the null keyword saying something is empty) is interpreted as `False`.\n", "Nearly everything else is interpreted as `True`.\n", "\n", "* In Python, `in` checks if an item is **contained within** a set-like Python type (see example below). \\\n", "For instance, `x in array_y` tests if the value of `x` is in `array_y` and returns `True` if it is.\n", "It also works for strings and substrings (so doing `'biol' in 'nanobiology'` would return\n", "`True`), and for checking if something is in the keys of a dictionary.\n", "The inverse function `not in` is also valid, but returns the inverse.\n", "\n", "* A **command or function** can itself return `True` or `False` which may be useful for catching errors or exceptions, or more complex behavior \n", "(e.g., a function that checks whether or not a simulated cell is touching other cells). More in this in a [later chapter on functions](../chapter8/functions-intro.md)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# Define a list of biomolecules\n", "molecules = ['protein', 'DNA', 'RNA', 'lipid']\n", "\n", "# Check if 'lipid' is in the list\n", "if 'lipid' in molecules:\n", " print(\"'lipid' is in the list of molecules.\")\n", "else:\n", " print(\"'lipid' is not in the list of molecules.\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{exercise}\n", ":class: dropdown\n", "Use the code cell below to explore the ways of obtaining True/False.\n", "\n", "1. Define a list, a tuple, a dictionary, and a string. Make them either empty or non-empty. Check whether they're True or False.\n", "\n", "2. Define a string and check how `in` works on it.\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Your code here" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-096011724723bedd", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Logical operations\n", "\n", "Python also allows you to **build the `expression` out of logical combinations of several conditions** using the logical (Boolean) operators `and`, `or`, and `not`. \n", "\n", "```{admonition} Logical operators\n", ":class: important\n", "`and` evaluates to `True` if **both** conditions are `True` \\\n", "`or` evaluates to `True` if **either** condition is `True` \\\n", "`not`evaluates to `True` if condition is `not True`\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if True and False:\n", " print(\"This will not be printed\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if True or False:\n", " print(\"This will be printed\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if not 5 > 6:\n", " print(\"We have already seen 'not' in previous examples. Here, we also combine with an comparison\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if not 5 != 5:\n", " print(\"This is a very silly example (hard to read, bad coding!)\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if 5 < 6 and 10 > 9: \n", " print(\"An example of combining conditional expressions with 'and'\")" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-8a0f0f9e5985f291", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "```{exercise}\n", ":class: dropdown\n", "Try the following examples using the `if` statement:\n", "\n", "a. Check both if 5 is smaller than 6 and if 10 is smaller or equal than 9.\n", "\n", "b. Do you think that the statement `not False or True` evaluates to `True` or `False`? \n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# Your code here" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-a09e89673e9b20d3", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "To understand what happened in part *b* of this exercise, we have to know whether Python first performs the operation `False or True` or if it performs the operation `not False` first. \n", "\n", "You can learn about the **order in which Python does things** in the documentation on [operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence). In the example above, we can see that the `not` operator got precedence and Python performed the `not` before it performed the `or`. \n", "\n", "What if we wanted to have Python perform the `or` first? You do this by enclosing `True or False` in **brackets**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "if not (False or True):\n", " print(\"not (False or True) is False so this will not be printed\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "thebe-remove-input-init" ] }, "outputs": [], "source": [ "import micropip\n", "await micropip.install(\"jupyterquiz\")\n", "from jupyterquiz import display_quiz\n", "import json\n", "\n", "with open(\"questions5.json\", \"r\") as file:\n", " questions=json.load(file)\n", " \n", "display_quiz(questions, border_radius=0)" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-e8a75bf958008fea", "locked": true, "schema_version": 3, "solution": false, "task": false }, "tags": [] }, "source": [ "## Elif and else statements\n", "\n", "In Python, you can combine the `if` statement with `elif` and `else` commands. This allows you to tell Python what to do in case the starting `if` statement was `False`. \n", "\n", "`elif` (standing for \"else if\") is a command that allows you to **check another condition** if the condition of the starting `if` is `False`. Note that if the `if` criterion is `True`, the `elif` statement will be skipped and not checked. \n", "\n", "`else` is a command that allows you to execute some code if **all of the `if` and all the `elif` are `False`**. \n", "\n", "```\n", "if expression_1:\n", " executed if expression_1 is True\n", "elif expression_2:\n", " executed if expression_1 is False and expression_2 is True\n", "else:\n", " executed if both expression_1 and expression_2 are False\n", "```\n", "\n", "Note that to be part of the logical chain, all the `elif`s and the last `else` must **follow directly** after each other's code blocks with no other code in between. \n", "A new `if` always **starts a new chain**. \n", "You can see how this works in the following examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a < 6:\n", " print(\"a is less than 6\")\n", "else:\n", " print(\"a is not less than 6\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a < 6: \n", " print(\"the 'if' statement found that a is less than 6\")\n", "elif a < 6:\n", " print(\"this will never get printed!\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "a = 5\n", "if a < 6: \n", " print(\"the first if found that a is less than 6\")\n", "if a < 6:\n", " print(\"unlike elif, a second if will get executed.\")" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": false, "grade_id": "cell-bcd1475b5312a9de", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Since the code inside your `if` code block is just regular code, you can also add another `if` statement inside that code block. This creates a **nested `if` statement** inside your first `if`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-output" ] }, "outputs": [], "source": [ "# An example of a nested if statement\n", "a = 4\n", "if a < 6 and a >= 0:\n", " if a > 3:\n", " print(\"the value of a is 4 or 5\")\n", " else:\n", " print(\"the value of a is 0, 1, 2, or 3\")\n", "else:\n", " print(\"none of these are the case\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that **indendation matters** also in nested statements! " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "thebe-remove-input-init" ] }, "outputs": [], "source": [ "import micropip\n", "await micropip.install(\"jupyterquiz\")\n", "from jupyterquiz import display_quiz\n", "import json\n", "\n", "with open(\"questions6.json\", \"r\") as file:\n", " questions=json.load(file)\n", " \n", "display_quiz(questions, border_radius=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## *(Optional)* The match case statement\n", "\n", "In addition to `if-elif-else`, there is also the `match case` conditional statement, in which we first pass a parameter to `match` and then check with which `case` the parameter is satisfied. \n", "If a match is found, the corresponding code block is executed.\n", "If no match is found, a default action will take place; in syntax, this is denoted with the `_` wildcard character.\n", "\n", "The match case conditional statement follows this syntax:\n", "\n", "```\n", "match parameter:\n", " case pattern1:\n", " code block for pattern1\n", " case pattern2:\n", " code block for pattern2\n", " ...\n", " case patterN:\n", " code block for patternN\n", " case _:\n", " default code block\n", "```\n", "\n", "Let's check out a simple example. Copy-paste code blocks below to your VS Code to run them, because `input` is buggy in the Jupyter book.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "# Ask user input\n", "number = int(input(\"Enter an integer number between 1 and 3: \"))\n", "\n", "# Inform user which number was inputed\n", "match number:\n", " case 1:\n", " print(\"One\")\n", " case 2:\n", " print(\"Two\")\n", " case 3:\n", " print(\"Three\")\n", " case _:\n", " print(\"Number not between 1 and 3\")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just as in `if-elif-else`, it's also possible to use logical operators (such as `|` for OR) in `match-case`. Moreover, we can use `if` within `match-case`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "# Ask user input\n", "number = int(input(\"Enter an integer number between 1 and 3: \"))\n", "\n", "# Inform user which number was inputed\n", "match number:\n", " case 1 | 2:\n", " print(\"One or Two\")\n", " case 3:\n", " print(\"Three\")\n", " case _:\n", " print(\"Number not between 1 and 3\")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{exercise}\n", ":class: dropdown\n", "In the code above, try to give number 4.1 as user-inputed number. Does the code work? If not, how would you fix it?\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "# Ask user input\n", "number = int(input(\"Enter an integer number: \"))\n", "\n", "# Inform user whether the inputed number is positive, negative, or zero\n", "match number:\n", " case number if number > 0:\n", " print(\"Positive\")\n", " case number if number < 0:\n", " print(\"Negative\")\n", " case _:\n", " print(\"Zero\")\n", "```\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{exercise}\n", ":class: dropdown\n", "Write code that performs the same two actions as above (informing about a number being 1, 2, or 3, and a number being positive, negative, or zero), but using `if-elif-else` instead of `match-case`.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more examples how to use `match-case`, check out this [website](https://www.geeksforgeeks.org/python-match-case-statement/)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} Usage of if-elif-else and match-case\n", ":class: tip\n", "\n", "When should we use `if-elif-else`, and when `match-case`?\n", "\n", "`if-elif-else` is more straightforward for simple condition checks, Boolean expressions, or when you need to perform comparisons between variables or evaluate more complex logic.\n", "On the other hand, `match-case` is more concise in complex scenarios, so you can use it to match against complex patterns or when you need a clear and concise way to handle multiple literal cases. In this context, \"literal cases\" refers to specific, concrete values or conditions that you want to match directly, without needing any complex logic or expressions.\n", "\n", "```" ] } ], "metadata": { "celltoolbar": "Create Assignment", "jupytext": { "formats": "ipynb,md" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.11.4" }, "toc": { "base_numbering": "3", "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 4 }