{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Lesson A6 – Conditions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this part of the tutorial we learn about what is `True` and `False` in Python. Testing if a certain condition is fulfilled, is a vital element of programming." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Emtpy type" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the context of conditions and testing them, it is also nice to have a representation for an absent value in the sense of an \"unset\" or \"no-value\" value. In Python there is a specific data type for an empty value, which is called `None`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# None\n", "n = None\n", "print(type(n))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "None is not nothing but a full-fledged exiting object. None can be passed to and returned\n", "by functions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A boolean variable is a data type which can assume only one of two values: `True` or `False`." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# boolean\n", "b = True\n", "print(type(b))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other data types can be converted into boolean data types with the `bool()` function, e.g. the integer 1 is converted to True while the integer 0 is converted to False. You can even convert strings to booleans. In fact every defined, non-empty object evaluates to True. `None` as an empty-value evaluates to False. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n", "False\n" ] } ], "source": [ "print(bool(1))\n", "print(bool(0))\n", "print(bool(\"False\"))\n", "print(bool(None))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Advanced" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because of this relation we can also kind of calculate with boolean values." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "run_control": { "marked": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "2\n", "1\n" ] } ], "source": [ "print(True * False)\n", "print(True + True)\n", "print(True + True * False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Empty collections evaluate to False as well." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "run_control": { "marked": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "list_empty = []\n", "print(bool(list_empty))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "True and False play an important role, when you want to test for certain\n", "conditions. You can compare things with the bit-wise operators summarised in the table below.\n", "\n", "| Operator | Meaning |\n", "|-------------|---------------------------------------------|\n", "| `a == b` | True, if `a` equal to `b` |\n", "| `a != b` | True, if `a` unequal to `b` |\n", "| `a < b` | True, if `a` less than `b` |\n", "| `a > b` | True, if `a` greater than `b` |\n", "| `a <= b` | True, if `a` less than or equal to `b` |\n", "| `a >= b` | True, if `a` greater than or equal to `b` | \n", "| `a & b` | True, if `a` AND `b` are True |\n", "| `a | b` | True, if `a` AND/OR `b` are True |\n", "| `a ^ b` | True, if `a` XOR `b` are True |" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, that the \"equal\"-operator is `==` instead of just `=` since a single equal sign is already used for variable assignments." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "print(1 == 1) # equal?\n", "print(1 != 1) # not equal?" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True? True\n", "True AND True? True\n", "True AND True? True\n", "True AND/OR True? True\n", "True AND/OR True? True\n", "True XOR True? True\n", "True XOR True? False\n" ] } ], "source": [ "print(\"True?\", 2 > 1) \n", "# 2 greater than 1?\n", "\n", "print(\"True AND True?\", (1 < 2) & (2 > 1))\n", "# 1 less than 2 AND 2 greater than 1?\n", "\n", "print(\"True AND True?\", 1 < 2 > 1) \n", "# 1 less than 2 AND 2 greater than 1? (Python short hand notation)\n", "\n", "print(\"True AND/OR True?\", (1 > 2) | (2 > 1))\n", "# 1 greater than 2 AND/OR 2 greater than 1? (At least one statement True)\n", "\n", "print(\"True AND/OR True?\", (1 < 2) | (2 > 1))\n", "# 1 less than 2 AND/OR 2 greater than 1? (At least one statement True)\n", "\n", "print(\"True XOR True?\", (1 > 2) ^ (2 > 1))\n", "# 1 greater than 2 OR 2 greater than 1? (Only one statement True)\n", "\n", "print(\"True XOR True?\", (1 < 2) ^ (2 > 1))\n", "# 1 less than 2 OR 2 greater than 1? (Only one statement True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These bit-wise operators have their literal expressions summarised in the table below which can be used instead. But be aware, that they do not always have the same meaning (see subsection [Advanced](#comparison_advanced) below)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "| Operator | Meaning |\n", "|-----------------|---------------------------------------------|\n", "| `a is b` | True, if `a` is identical to `b` |\n", "| `a is not b` | True, if `a` is not identical to `b` |\n", "| `a and b` | True, if `a` AND `b` are True |\n", "| `a or b` | True, if `a` AND/OR `b` are True |" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True AND True? True\n", "True OR True? True\n" ] } ], "source": [ "print(\"True AND True?\", (1 < 2) and (2 > 1))\n", "print(\"True OR True?\", (1 > 2) or (2 > 1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "### Advanced" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### The `is` operator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The literal `is` operator has a different meaning than the `==` operator." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "a = 1\n", "b = 1\n", "print(a is b) # identical?\n", "print(a is not b) # not identical?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But ..." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n" ] } ], "source": [ "a = 450\n", "b = 450\n", "print(a is b) # equal?\n", "print(a is not b) # not equal?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While `==` tests for value equality, `is` tests for object identity. Due to the\n", "way Python handles the storage of integer values for example, a stored 1\n", "is always the same object, which is true for a few other integers, too. A stored 450 on the other hand is only equal to\n", "another 450 by value but it is not the same object." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, while `bool(None)` evaluates to False, None is neither equal to False, nor is it the same object." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n", "True\n", "False\n", "False\n" ] } ], "source": [ "print(None is None)\n", "print(True is True)\n", "print(False is False)\n", "print(None is False)\n", "print(None is True)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n", "True\n", "False\n", "False\n" ] } ], "source": [ "print(None == None)\n", "print(True == True)\n", "print(False == False)\n", "print(None == False)\n", "print(None == True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On the other hand, True and False are equal to 1 and 0 by value (but are different object of course). " ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n" ] } ], "source": [ "print(True == 1)\n", "print(False == 0)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n" ] } ], "source": [ "print(True is 1)\n", "print(False is 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### The `and` and `or` operator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `and` and `or` operator may also not work as you expect so be careful:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n", "1\n" ] } ], "source": [ "print(1 and 2)\n", "print(2 and 1) \n", "# If True return the last True value (not True)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "0\n", "None\n" ] } ], "source": [ "print(1 and 0)\n", "print(0 and 1)\n", "print(None and 0)\n", "# If False return the first False value (not False)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n" ] } ], "source": [ "print(1 or 2)\n", "print(2 or 1)\n", "# If True return the first True value (not True)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "None\n" ] } ], "source": [ "print(None or 0)\n", "print(0 or None)\n", "# If False return the last value (not True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### The `in` operator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python there is additionally a literal comparison operator stating if an object is part of another one: the `in` operator. It can be for example used to discover if an object is contained in a container." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 in [1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## If and else" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So for now we can write straightforward programs as a series of statements that are executed one after the other. We get more flexibility in our code, when we test for conditions and do different things, depending on the outcome of the test. We can do this in Python using the `if` directive. Note, that the code block following the statement with the `if` directive is indented by 4 spaces. In this way Python knows, that this code block is subordinate and only to be executed if the `if` statement evaluates to True." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a is really equal to one\n" ] } ], "source": [ "a = 1\n", "if a == 1: # <- colon after the conditional statement\n", " print(\"a is really equal to one\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Note:** We had our first encounter here with something very essential to Python: __indention__. So far we used indention only for cosmetic reasons. Now that we use a directive that introduces some hierarchy of statements in our code, we need to make sure that the subordinate statements are indented. You need the same indention policy throughout your whole program. By convention indention is done by 4 spaces per hierarchy level.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can extend this with the `else`directive." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, World!\n" ] } ], "source": [ "a = \"Hello, World!\"\n", "\n", "# Test if the first character of the string `a` is not equal to \"X\"\n", "if a[0] != \"X\":\n", " print(a)\n", "else:\n", " print(\"I cannot work with this ...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can test also for several conditions, one by one with the `elif` directive." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I can use this\n" ] } ], "source": [ "a = [\"aspirin\", \"ethanol\"]\n", "\n", "# Test if the string \"aspirin\" is an element of the list `a`\n", "if \"aspirin\" in a:\n", " print(\"I can use this\")\n", " \n", "# Otherwise test if the string \"ethonal\" is an element of the list `a`\n", "elif \"ethanol\" in a:\n", " print(\"Ok, than I will use this\")\n", " \n", "# Otherwise ...\n", "else:\n", " print(\"I cannot work with this ...\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Try and except" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `if` and `else` to test if something is True and than act accordingly seems like a reasonable procedure to write programs that can deal with varying situations. With this \"asking for permission first before you do something\"-approach, you are often on the safe side. It is typical to Python that it also allows you to do it the other way round. In many cases, it can be better just to try something you want to do, and only act accordingly if something goes wrong. This is particularly nice if you are checking a condition that is true most of the time and leads to an exception if it is not. The magic words here are `try` and `except`." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "\n", "# Try to append a value to the list `a`\n", "try:\n", " a.append(4)\n", " \n", "# And if this does not work ... (but it does!)\n", "except AttributeError():\n", " pass # Do nothing\n", "\n", "print(a)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "run_control": { "marked": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I cannot work with this ...\n", "(1, 2, 3)\n" ] } ], "source": [ "a = (1, 2, 3)\n", "\n", "# Try to append a value to the tuple `a`\n", "try:\n", " a.append(4)\n", " \n", "# And if this does not work ... (and it doesn't!)\n", "except AttributeError:\n", " print(\"I cannot work with this ...\")\n", " \n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can additionally use the `else` and the `finally` directive to extend this." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Appended 4 to a\n", "[1, 2, 3, 4]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "\n", "try:\n", " # Let's see if this works ...\n", " a.append(4)\n", "except AttributeError:\n", " # Aha, it did not ...\n", " print(\"I cannot work with this ...\")\n", "else:\n", " # Yes, it worked!\n", " print(\"Appended 4 to a\")\n", "finally:\n", " # No matter if it worked ...\n", " print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can seem a bit more complex at first compared to the if-else variant because you need to anticipate which kind of error would be raised, if what you try to do fails. But depending on the individual case, the try-except variant can be also easier to understand. In any case it is a good thing that we can tackle conditional program execution from different angles. The if-else code of the last example could look like this by the way:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Appended 4 to a\n", "[1, 2, 3, 4]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "# Let's see if this works ...\n", "if isinstance(a, list):\n", " # Yes, it will work!\n", " a.append(4)\n", " print(\"Appended 4 to a\")\n", "else:\n", " # Aha, it will not ...\n", " print(\"I cannot work with this ...\")\n", "\n", "# No matter if it worked ...\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Note:** The `isinstance(object, type)` function is the preferred way of saying `type(object) is type`. \n", " \n", "
" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "165px" }, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }