diff --git a/chapter_00_intro/00_content.ipynb b/00_intro/00_content.ipynb
similarity index 98%
rename from chapter_00_intro/00_content.ipynb
rename to 00_intro/00_content.ipynb
index b3f20a3..a2e8778 100644
--- a/chapter_00_intro/00_content.ipynb
+++ b/00_intro/00_content.ipynb
@@ -8,7 +8,7 @@
}
},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_00_intro/00_content.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/00_intro/00_content.ipynb)."
]
},
{
@@ -750,10 +750,10 @@
"**Part A: Expressing Logic**\n",
"\n",
"- What is a programming language? What kind of words exist?\n",
- " - *Chapter 1*: [Elements of a Program ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb)\n",
- " - *Chapter 2*: [Functions & Modularization ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb)\n",
+ " - *Chapter 1*: [Elements of a Program ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb)\n",
+ " - *Chapter 2*: [Functions & Modularization ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb)\n",
"- What is the flow of execution? How can we form sentences from words?\n",
- " - *Chapter 3*: Conditionals & Exceptions\n",
+ " - *Chapter 3*: [Conditionals & Exceptions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb)\n",
" - *Chapter 4*: Recursion & Looping"
]
},
diff --git a/chapter_00_intro/01_exercises.ipynb b/00_intro/01_exercises.ipynb
similarity index 91%
rename from chapter_00_intro/01_exercises.ipynb
rename to 00_intro/01_exercises.ipynb
index 7f51a1d..c5082eb 100644
--- a/chapter_00_intro/01_exercises.ipynb
+++ b/00_intro/01_exercises.ipynb
@@ -4,35 +4,28 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_00_intro/02_exercises.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/00_intro/02_exercises.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 0: Introduction"
+ "# Chapter 0: Introduction (Coding Exercises)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## \"Coding\" Exercises"
+ "The exercises below assume that you have read [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/00_content.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "The exercises below assume that you have read [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/00_content.ipynb)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Mastering Markdown"
+ "## Mastering Markdown"
]
},
{
diff --git a/chapter_00_intro/02_review.ipynb b/00_intro/02_review.ipynb
similarity index 94%
rename from chapter_00_intro/02_review.ipynb
rename to 00_intro/02_review.ipynb
index 0f75bfe..9a8d7c2 100644
--- a/chapter_00_intro/02_review.ipynb
+++ b/00_intro/02_review.ipynb
@@ -4,21 +4,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 0: Introduction"
+ "# Chapter 0: Introduction (Review Questions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Review"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The questions below assume that you have read [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/00_content.ipynb).\n",
+ "The questions below assume that you have read [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/00_content.ipynb).\n",
"\n",
"Be concise in your answers! Most questions can be answered in *one* sentence."
]
@@ -27,7 +20,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Essay Questions "
+ "## Essay Questions "
]
},
{
@@ -90,7 +83,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### True / False Questions"
+ "## True / False Questions"
]
},
{
diff --git a/chapter_00_intro/static/cli_example.png b/00_intro/static/cli_example.png
similarity index 100%
rename from chapter_00_intro/static/cli_example.png
rename to 00_intro/static/cli_example.png
diff --git a/chapter_00_intro/static/example_python_users.png b/00_intro/static/example_python_users.png
similarity index 100%
rename from chapter_00_intro/static/example_python_users.png
rename to 00_intro/static/example_python_users.png
diff --git a/chapter_00_intro/static/growth_of_major_programming_languages.png b/00_intro/static/growth_of_major_programming_languages.png
similarity index 100%
rename from chapter_00_intro/static/growth_of_major_programming_languages.png
rename to 00_intro/static/growth_of_major_programming_languages.png
diff --git a/chapter_00_intro/static/growth_of_smaller_programming_languages.png b/00_intro/static/growth_of_smaller_programming_languages.png
similarity index 100%
rename from chapter_00_intro/static/growth_of_smaller_programming_languages.png
rename to 00_intro/static/growth_of_smaller_programming_languages.png
diff --git a/chapter_00_intro/static/logo.png b/00_intro/static/logo.png
similarity index 100%
rename from chapter_00_intro/static/logo.png
rename to 00_intro/static/logo.png
diff --git a/chapter_00_intro/static/xkcd.png b/00_intro/static/xkcd.png
similarity index 100%
rename from chapter_00_intro/static/xkcd.png
rename to 00_intro/static/xkcd.png
diff --git a/chapter_01_elements/00_content.ipynb b/01_elements/00_content.ipynb
similarity index 98%
rename from chapter_01_elements/00_content.ipynb
rename to 01_elements/00_content.ipynb
index ad71aa9..6003bd9 100644
--- a/chapter_01_elements/00_content.ipynb
+++ b/01_elements/00_content.ipynb
@@ -8,7 +8,7 @@
}
},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/00_content.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/00_content.ipynb)."
]
},
{
@@ -1165,7 +1165,7 @@
"source": [
"These addresses are *not* meaningful for anything other than checking if two variables reference the *same* object.\n",
"\n",
- "Obviously, `a` and `b` have the same *value* as revealed by the **equality operator** `==`: We say `a` and `b` \"evaluate equal.\" The resulting `True` - and the `False` further below - is yet another data type, a so-called **boolean**. We look into them in [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_03_conditionals/00_content.ipynb#Boolean-Expressions)."
+ "Obviously, `a` and `b` have the same *value* as revealed by the **equality operator** `==`: We say `a` and `b` \"evaluate equal.\" The resulting `True` - and the `False` further below - is yet another data type, a so-called **boolean**. We look into them in [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb#Boolean-Expressions)."
]
},
{
@@ -1342,7 +1342,7 @@
"source": [
"Different types imply different behaviors for the objects. The `b` object, for example, may be \"asked\" if it is a whole number with the [is_integer() ](https://docs.python.org/3/library/stdtypes.html#float.is_integer) \"functionality\" that comes with *every* `float` object.\n",
"\n",
- "Formally, we call such type-specific functionalities **methods** (i.e., as opposed to functions) and we look at them in detail in [Chapter 10 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_10_classes/00_content.ipynb). For now, it suffices to know that we access them with the **dot operator** `.` on the object. Of course, `b` is a whole number, which the boolean object `True` tells us."
+ "Formally, we call such type-specific functionalities **methods** (i.e., as opposed to functions) and we look at them in detail in [Chapter 10 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/10_classes/00_content.ipynb). For now, it suffices to know that we access them with the **dot operator** `.` on the object. Of course, `b` is a whole number, which the boolean object `True` tells us."
]
},
{
@@ -1934,7 +1934,7 @@
}
},
"source": [
- "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the built-in [sum() ](https://docs.python.org/3/library/functions.html#sum) and [len() ](https://docs.python.org/3/library/functions.html#len) functions (cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_08_mfr/00_content.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone."
+ "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the built-in [sum() ](https://docs.python.org/3/library/functions.html#sum) and [len() ](https://docs.python.org/3/library/functions.html#len) functions (cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/08_mfr/00_content.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone."
]
},
{
@@ -2136,7 +2136,7 @@
"\n",
"At the same time, for a beginner's course, it is often easier to code linearly.\n",
"\n",
- "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for an analysis."
+ "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for an analysis."
]
}
],
diff --git a/01_elements/01_exercises.ipynb b/01_elements/01_exercises.ipynb
new file mode 100644
index 0000000..d073a26
--- /dev/null
+++ b/01_elements/01_exercises.ipynb
@@ -0,0 +1,172 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/01_exercises.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 1: Elements of a Program (Coding Exercises)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The exercises below assume that you have read the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb) of Chapter 1.\n",
+ "\n",
+ "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Printing Output"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q1**: *Concatenate* `greeting` and `audience` below with the `+` operator and print out the resulting message `\"Hello World\"` with only *one* call of the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function!\n",
+ "\n",
+ "Hint: You may have to \"add\" a space character in between `greeting` and `audience`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "greeting = \"Hello\"\n",
+ "audience = \"World\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q2**: How is your answer to **Q1** an example of the concept of **operator overloading**?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q3**: Read the documentation on the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function! How can you print the above message *without* concatenating `greeting` and `audience` first in *one* call of [print() ](https://docs.python.org/3/library/functions.html#print)?\n",
+ "\n",
+ "Hint: The `*objects` in the documentation implies that we can put several *expressions* (i.e., variables) separated by commas within the same call of the [print() ](https://docs.python.org/3/library/functions.html#print) function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q4**: What does the `sep=\" \"` mean in the documentation on the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function? Adjust and use it to print out the three names referenced by `first`, `second`, and `third` on *one* line separated by *commas* with only *one* call of the [print() ](https://docs.python.org/3/library/functions.html#print) function!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "first = \"Anthony\"\n",
+ "second = \"Berta\"\n",
+ "third = \"Christian\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q5**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Adjust and use it within the `for`-loop to print the numbers `1` through `10` on *one* line with only *one* call of the [print() ](https://docs.python.org/3/library/functions.html#print) function!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:\n",
+ " print(...)"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "sideBar": true,
+ "skip_h1_title": true,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/01_elements/02_exercises.ipynb b/01_elements/02_exercises.ipynb
new file mode 100644
index 0000000..5ae269c
--- /dev/null
+++ b/01_elements/02_exercises.ipynb
@@ -0,0 +1,218 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/02_exercises.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 1: Elements of a Program (Coding Exercises)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The exercises below assume that you have read the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb) of Chapter 1.\n",
+ "\n",
+ "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Simple `for`-loops"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`for`-loops are extremely versatile in Python. That is different from many other programming languages.\n",
+ "\n",
+ "As shown in the first example in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q1**: Fill in the *condition* of the `if` statement such that only numbers divisible by `3` are printed! Adjust the call of the [print() ](https://docs.python.org/3/library/functions.html#print) function such that the `for`-loop prints out all the numbers on *one* line of output!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in numbers:\n",
+ " if ...:\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Instead of looping over an *existing* object referenced by a variable like `numbers`, we may also create a *new* object within the `for` statement and loop over it directly. For example, below we write out the `list` object as a *literal*.\n",
+ "\n",
+ "Generically, the objects contained in a `list` objects are referred to as its **elements**. We reflect that in the name of the *target* variable `element` that is assigned a different number in every iteration of the `for`-loop. While we could use *any* syntactically valid name, it is best to choose one that makes sense in the context (e.g., `number` in `numbers`).\n",
+ "\n",
+ "**Q2**: Fill in the condition of the `if` statement such that only numbers consisting of *one* digit are printed out! As before, print out all the numbers on *one* line of output!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for element in [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]:\n",
+ " if ...:\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "An easy way to loop over a `list` object in a sorted manner, is to wrap it with the built-in [sorted() ](https://docs.python.org/3/library/functions.html#sorted) function.\n",
+ "\n",
+ "**Q3**: Fill in the condition of the `if` statement such that only odd numbers are printed out! Put all the numbers on *one* line of output!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in sorted(numbers):\n",
+ " if ...:\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Whenever we want to loop over numbers representing a [series ](https://en.wikipedia.org/wiki/Series_%28mathematics%29) in the mathematical sense (i.e., a rule to calculate the next number from its predecessor), we may be able to use the [range() ](https://docs.python.org/3/library/functions.html#func-range) built-in.\n",
+ "\n",
+ "For example, to loop over the whole numbers from `0` to `9` (both including) in order, we could write them out in a `list` like below.\n",
+ "\n",
+ "**Q4**: Fill in the call to the [print() ](https://docs.python.org/3/library/functions.html#print) function such that all the numbers are printed on *one* line ouf output!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q5**: Read the documentation on the [range() ](https://docs.python.org/3/library/functions.html#func-range) built-in! It may be used with either one, two, or three expressions \"passed\" in. What do `start`, `stop`, and `step` mean? Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to mimic the output of **Q4**!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in range(...):\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q6**: Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to print out *all* numbers from `1` to `10` (both including)!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in range(...):\n",
+ " print(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q7**: Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to print out the *even* numbers from `1` to `10` (both including)! Do *not* use an `if` statement to accomplish this!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in range(...):\n",
+ " print(...)"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "sideBar": true,
+ "skip_h1_title": true,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/chapter_01_elements/02_content.ipynb b/01_elements/03_content.ipynb
similarity index 96%
rename from chapter_01_elements/02_content.ipynb
rename to 01_elements/03_content.ipynb
index ea72a59..74c3477 100644
--- a/chapter_01_elements/02_content.ipynb
+++ b/01_elements/03_content.ipynb
@@ -8,7 +8,7 @@
}
},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/02_content.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/03_content.ipynb)."
]
},
{
@@ -19,7 +19,7 @@
}
},
"source": [
- "# Chapter 1: Elements of a Program (Part 2)"
+ "# Chapter 1: Elements of a Program (continued)"
]
},
{
@@ -367,7 +367,7 @@
}
},
"source": [
- "Some variables magically exist when a Python process is started or are added by Jupyter. We may safely ignore the former until [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb) and the latter for good."
+ "Some variables magically exist when a Python process is started or are added by Jupyter. We may safely ignore the former until [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb) and the latter for good."
]
},
{
@@ -679,7 +679,7 @@
}
},
"source": [
- "Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for built-in functionalities and to implement object-oriented features as we see in [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb). We must *not* use this style for variables!"
+ "Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for built-in functionalities and to implement object-oriented features as we see in [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb). We must *not* use this style for variables!"
]
},
{
@@ -960,7 +960,7 @@
"source": [
"Let's change the first element of `x`.\n",
"\n",
- "[Chapter 7 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_07_sequences/00_content.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as yet another operator, namely the **indexing operator**. So, `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object we put in the list. The indexing operator must be an operator as we merely *read* the first element and do not change anything in memory permanently.\n",
+ "[Chapter 7 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/07_sequences/00_content.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as yet another operator, namely the **indexing operator**. So, `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object we put in the list. The indexing operator must be an operator as we merely *read* the first element and do not change anything in memory permanently.\n",
"\n",
"Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB ](https://en.wikipedia.org/wiki/MATLAB), [R ](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata ](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra ](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)."
]
@@ -1136,7 +1136,7 @@
"\n",
"In simple words, anything that may be used on the *right-hand* side of an assignment statement without creating a `SyntaxError` is an expression.\n",
"\n",
- "What we have said about *individual* operators before, namely that they have *no* permanent side effects in memory, actually belongs here, to begin with: The absence of any *permanent* side effects is the characteristic property of expressions, and all the code cells in the \"*(Arithmetic) Operators*\" section in the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#%28Arithmetic%29-Operators) of this chapter are examples of expressions.\n",
+ "What we have said about *individual* operators before, namely that they have *no* permanent side effects in memory, actually belongs here, to begin with: The absence of any *permanent* side effects is the characteristic property of expressions, and all the code cells in the \"*(Arithmetic) Operators*\" section in the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#%28Arithmetic%29-Operators) of this chapter are examples of expressions.\n",
"\n",
"The simplest possible expressions contain only one variable or literal. The output below a code cell is Jupyter's way of returning the reference to the object to us!\n",
"\n",
@@ -1406,7 +1406,7 @@
}
},
"source": [
- "... calling the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function does *neither* change the memory *nor* evaluate to an object (disregarding the `None` object explained in [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb#Function-Definitions)). We could view changing the computer's screen as a side effect but this is outside of Python's memory!\n",
+ "... calling the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function does *neither* change the memory *nor* evaluate to an object (disregarding the `None` object explained in [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb#Function-Definitions)). We could view changing the computer's screen as a side effect but this is outside of Python's memory!\n",
"\n",
"Also, the cell below has *no* output! It only looks like it does as Jupyter redirects whatever [print() ](https://docs.python.org/3/library/functions.html#print) writes to the \"screen\" to below a cell. We see a difference to the expressions above in that there are no brackets `[...]` next to the output showing the execution count number."
]
diff --git a/chapter_01_elements/03_exercises.ipynb b/01_elements/04_exercises.ipynb
similarity index 91%
rename from chapter_01_elements/03_exercises.ipynb
rename to 01_elements/04_exercises.ipynb
index d9d0bbf..f1cca6d 100644
--- a/chapter_01_elements/03_exercises.ipynb
+++ b/01_elements/04_exercises.ipynb
@@ -4,28 +4,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/03_exercises.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/04_exercises.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 1: Elements of a Program (Part 2)"
+ "# Chapter 1: Elements of a Program (Coding Exercises)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Coding Exercises"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The exercises below assume that you have read the second part of [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/02_content.ipynb).\n",
+ "The exercises below assume that you have read the [second part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb) Chapter 1.\n",
"\n",
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
]
@@ -34,7 +27,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Python as a Calculator"
+ "## Python as a Calculator"
]
},
{
diff --git a/chapter_01_elements/04_summary.ipynb b/01_elements/05_summary.ipynb
similarity index 90%
rename from chapter_01_elements/04_summary.ipynb
rename to 01_elements/05_summary.ipynb
index 9f52d19..c3b6339 100644
--- a/chapter_01_elements/04_summary.ipynb
+++ b/01_elements/05_summary.ipynb
@@ -8,19 +8,7 @@
}
},
"source": [
- "\n",
- "# Chapter 1: Elements of a Program"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "slideshow": {
- "slide_type": "skip"
- }
- },
- "source": [
- "## TL;DR"
+ "# Chapter 1: Elements of a Program (TL;DR)"
]
},
{
@@ -57,7 +45,7 @@
" - distinct and well-contained areas/parts of the memory that hold the actual data\n",
" - the concept by which Python manages the memory for us\n",
" - can be classified into objects of the same **type** (i.e., same abstract \"structure\" but different concrete data)\n",
- " - built-in objects (incl. **literals**) vs. user-defined objects (cf., [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb))\n",
+ " - built-in objects (incl. **literals**) vs. user-defined objects (cf., [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb))\n",
" - e.g., `1`, `1.0`, and `\"one\"` are three different objects of distinct types that are also literals (i.e., by the way we type them into the command line Python knows what the value and type are)\n",
"\n",
"\n",
@@ -92,14 +80,14 @@
" - ignored by Python\n",
"\n",
"\n",
- "- functions (cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb))\n",
+ "- functions (cf., [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb))\n",
" - named sequences of instructions\n",
" - the smaller parts in a larger program\n",
" - make a program more modular and thus easier to understand\n",
" - include [built-in functions ](https://docs.python.org/3/library/functions.html) like [print() ](https://docs.python.org/3/library/functions.html#print), [sum() ](https://docs.python.org/3/library/functions.html#sum), or [len() ](https://docs.python.org/3/library/functions.html#len)\n",
"\n",
"\n",
- "- flow control (cf., [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_03_conditionals/00_content.ipynb) and [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_04_iteration/00_content.ipynb))\n",
+ "- flow control (cf., [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb) and [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb))\n",
" - expression of **business logic** or an **algorithm**\n",
" - conditional execution of parts of a program (e.g., `if` statements)\n",
" - repetitive execution of parts of a program (e.g., `for`-loops)"
diff --git a/chapter_01_elements/05_review.ipynb b/01_elements/06_review.ipynb
similarity index 90%
rename from chapter_01_elements/05_review.ipynb
rename to 01_elements/06_review.ipynb
index d8ec024..d975603 100644
--- a/chapter_01_elements/05_review.ipynb
+++ b/01_elements/06_review.ipynb
@@ -4,21 +4,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 1: Elements of a Program"
+ "# Chapter 1: Elements of a Program (Review Questions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Content Review"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The questions below assume that you have read the [first ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb) and the [second ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/02_content.ipynb) part of Chapter 1.\n",
+ "The questions below assume that you have read the [first ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb) and the [second ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb) part of Chapter 1.\n",
"\n",
"Be concise in your answers! Most questions can be answered in *one* sentence."
]
@@ -27,7 +20,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Essay Questions "
+ "## Essay Questions "
]
},
{
@@ -118,7 +111,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### True / False Questions"
+ "## True / False Questions"
]
},
{
diff --git a/chapter_01_elements/06_resources.ipynb b/01_elements/07_resources.ipynb
similarity index 98%
rename from chapter_01_elements/06_resources.ipynb
rename to 01_elements/07_resources.ipynb
index bdc2e29..c73cc49 100644
--- a/chapter_01_elements/06_resources.ipynb
+++ b/01_elements/07_resources.ipynb
@@ -8,19 +8,7 @@
}
},
"source": [
- "\n",
- "# Chapter 1: Elements of a Program"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "slideshow": {
- "slide_type": "skip"
- }
- },
- "source": [
- "## Further Resources"
+ "# Chapter 1: Elements of a Program (Further Resources)"
]
},
{
@@ -58,7 +46,7 @@
" "
],
"text/plain": [
- ""
+ ""
]
},
"execution_count": 1,
diff --git a/chapter_02_functions/00_content.ipynb b/02_functions/00_content.ipynb
similarity index 95%
rename from chapter_02_functions/00_content.ipynb
rename to 02_functions/00_content.ipynb
index 4d18040..964ecaa 100644
--- a/chapter_02_functions/00_content.ipynb
+++ b/02_functions/00_content.ipynb
@@ -8,7 +8,7 @@
}
},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/00_content.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/00_content.ipynb)."
]
},
{
@@ -30,7 +30,7 @@
}
},
"source": [
- "In [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we simply typed the code to calculate the average of the even numbers in a list of whole numbers into several code cells. Then, we executed them one after another. We had no way of *reusing* the code except for either executing cells multiple times. And, whenever we find ourselves doing repetitive manual work, we can be sure that there must be a way of automating what we are doing.\n",
+ "In [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we simply typed the code to calculate the average of the even numbers in a list of whole numbers into several code cells. Then, we executed them one after another. We had no way of *reusing* the code except for either executing cells multiple times. And, whenever we find ourselves doing repetitive manual work, we can be sure that there must be a way of automating what we are doing.\n",
"\n",
"This chapter shows how Python offers language constructs that let us **define** functions ourselves that we may then **call** just like the built-in ones. Also, we look at how we can extend our Python installation with functionalities written by other people."
]
@@ -307,7 +307,7 @@
}
},
"source": [
- "To execute a function, we **call** it with the **call operator** `()` as shown many times in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb) and above.\n",
+ "To execute a function, we **call** it with the **call operator** `()` as shown many times in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb) and above.\n",
"\n",
"If we are unsure whether a variable references a function or not, we can verify that with the built-in [callable() ](https://docs.python.org/3/library/functions.html#callable) function.\n",
"\n",
@@ -538,7 +538,7 @@
}
},
"source": [
- "Notice the subtle difference compared to the behavior of the `//` operator in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb##%28Arithmetic#%29-Operators) that \"rounds\" towards minus infinity: [int() ](https://docs.python.org/3/library/functions.html#int) always \"rounds\" towards `0`."
+ "Notice the subtle difference compared to the behavior of the `//` operator in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb##%28Arithmetic#%29-Operators) that \"rounds\" towards minus infinity: [int() ](https://docs.python.org/3/library/functions.html#int) always \"rounds\" towards `0`."
]
},
{
@@ -869,7 +869,7 @@
}
},
"source": [
- "We may create so-called *user-defined* **functions** with the `def` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)). To extend an already familiar example, we reuse the introductory example from [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#Best-Practices) in its final Pythonic version and transform it into the function `average_evens()` below. We replace the variable name `numbers` with `integers` for didactical purposes in the first couple of examples.\n",
+ "We may create so-called *user-defined* **functions** with the `def` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)). To extend an already familiar example, we reuse the introductory example from [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Best-Practices) in its final Pythonic version and transform it into the function `average_evens()` below. We replace the variable name `numbers` with `integers` for didactical purposes in the first couple of examples.\n",
"\n",
"A function's **name** must be chosen according to the same naming rules as ordinary variables since Python manages function names like variables. In this book, we further adopt the convention of ending function names with parentheses `()` in text cells for faster comprehension when reading (i.e., `average_evens()` vs. `average_evens`). These are *not* part of the name but must always be written out in the `def` statement for syntactic reasons.\n",
"\n",
@@ -881,7 +881,7 @@
"\n",
"A function may specify an *explicit* **return value** (i.e., \"result\" or \"output\") with the `return` statement (cf., [reference ](https://docs.python.org/3/reference/simple_stmts.html#the-return-statement)): Functions that have one are considered **fruitful**; otherwise, they are **void**. Functions of the latter kind are still useful because of their **side effects**. For example, the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function changes what we see on the screen. Strictly speaking, [print() ](https://docs.python.org/3/library/functions.html#print) and other void functions also have an *implicit* return value, namely the `None` object.\n",
"\n",
- "A function should define a **docstring** that describes what it does in a short subject line, what parameters it expects (i.e., their types), and what it returns, if anything. A docstring is a syntactically valid multi-line string (i.e., type `str`) defined within **triple-double quotes** `\"\"\"`. Strings are covered in depth in [Chapter 6 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_06_text/00_content.ipynb#The-str-Type). Widely adopted standards for docstrings are [PEP 257 ](https://www.python.org/dev/peps/pep-0257/) and section 3.8 of [Google's Python Style Guide ](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)."
+ "A function should define a **docstring** that describes what it does in a short subject line, what parameters it expects (i.e., their types), and what it returns, if anything. A docstring is a syntactically valid multi-line string (i.e., type `str`) defined within **triple-double quotes** `\"\"\"`. Strings are covered in depth in [Chapter 6 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/06_text/00_content.ipynb#The-str-Type). Widely adopted standards for docstrings are [PEP 257 ](https://www.python.org/dev/peps/pep-0257/) and section 3.8 of [Google's Python Style Guide ](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)."
]
},
{
@@ -1012,7 +1012,7 @@
"source": [
"Its value may seem awkward at first: It consists of a location showing where the function is defined (i.e., `__main__` here, which is Python's way of saying \"in this notebook\") and the signature wrapped inside angle brackets `<` and `>`.\n",
" \n",
- "The angle brackets are a convention to indicate that the value may *not* be used as a *literal* (i.e., typed back into another code cell). [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb) introduces the concept of a **text representation** of an object, which is related to the *semantic* meaning of an object's value as discussed in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#Value-/-\"Meaning\"), and the angle brackets convention is one such way to represent an object as text. When executed, the angle brackets cause a `SyntaxError` because Python expects the `<` operator to come with an operand on both sides (cf., [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_03_conditionals/00_content.ipynb#Relational-Operators))."
+ "The angle brackets are a convention to indicate that the value may *not* be used as a *literal* (i.e., typed back into another code cell). [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb) introduces the concept of a **text representation** of an object, which is related to the *semantic* meaning of an object's value as discussed in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Value-/-\"Meaning\"), and the angle brackets convention is one such way to represent an object as text. When executed, the angle brackets cause a `SyntaxError` because Python expects the `<` operator to come with an operand on both sides (cf., [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb#Relational-Operators))."
]
},
{
@@ -1148,7 +1148,7 @@
"\n",
"Returns:\n",
" average (float)\n",
- "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/chapter_02_functions/\n",
+ "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/02_functions/\n",
"\u001b[0;31mType:\u001b[0m function\n"
]
},
@@ -1197,7 +1197,7 @@
"\u001b[0;34m\u001b[0m \u001b[0mevens\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mn\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mintegers\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0maverage\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mevens\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mevens\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0maverage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/chapter_02_functions/\n",
+ "\u001b[0;31mFile:\u001b[0m ~/repos/intro-to-python/02_functions/\n",
"\u001b[0;31mType:\u001b[0m function\n"
]
},
@@ -1647,7 +1647,7 @@
"source": [
"[PythonTutor ](http://pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0A%0Adef%20average_wrong%28integers%29%3A%0A%20%20%20%20evens%20%3D%20%5Bn%20for%20n%20in%20numbers%20if%20n%20%25%202%20%3D%3D%200%5D%0A%20%20%20%20average%20%3D%20sum%28evens%29%20/%20len%28evens%29%0A%20%20%20%20return%20average%0A%0Aresult%20%3D%20average_wrong%28%5B123,%20456,%20789%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) is again helpful at visualizing the error interactively: Creating the `list` object `evens` eventually references takes *16* computational steps, namely two for managing the list comprehension, one for setting up an empty `list` object, *twelve* for filling it with elements derived from `numbers` in the global scope (i.e., that is the error), and one to make `evens` reference it (cf., steps 6-21).\n",
"\n",
- "The frames logic shown by PythonTutor is the mechanism with which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_04_iteration/00_content.ipynb#Trivial-Example:-Countdown). It is the reason why we may reuse the same names for the parameters and variables inside both `average_evens()` and `average_wrong()` without Python mixing them up. So, as we already read in the [Zen of Python ](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`), and a frame is just a special kind of namespace."
+ "The frames logic shown by PythonTutor is the mechanism with which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/04_iteration/00_content.ipynb#Trivial-Example:-Countdown). It is the reason why we may reuse the same names for the parameters and variables inside both `average_evens()` and `average_wrong()` without Python mixing them up. So, as we already read in the [Zen of Python ](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`), and a frame is just a special kind of namespace."
]
},
{
@@ -2021,7 +2021,7 @@
}
},
"source": [
- "So far, we have specified only one parameter in each of our user-defined functions. In [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#%28Arithmetic%29-Operators), however, we saw the built-in [divmod() ](https://docs.python.org/3/library/functions.html#divmod) function take two arguments. And, the order in which they are passed in matters! Whenever we call a function and list its arguments in a comma separated manner, we say that we pass in the arguments *by position* or refer to them as **positional arguments**."
+ "So far, we have specified only one parameter in each of our user-defined functions. In [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#%28Arithmetic%29-Operators), however, we saw the built-in [divmod() ](https://docs.python.org/3/library/functions.html#divmod) function take two arguments. And, the order in which they are passed in matters! Whenever we call a function and list its arguments in a comma separated manner, we say that we pass in the arguments *by position* or refer to them as **positional arguments**."
]
},
{
@@ -3012,7 +3012,7 @@
"source": [
"The main point of having functions without a reference to them is to use them in a situation where we know ahead of time that we use the function only *once*.\n",
"\n",
- "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm (cf., [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_08_mfr/00_content.ipynb#Lambda-Expressions))."
+ "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm (cf., [Chapter 8 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/08_mfr/00_content.ipynb#Lambda-Expressions))."
]
}
],
diff --git a/chapter_02_functions/01_exercises.ipynb b/02_functions/01_exercises.ipynb
similarity index 92%
rename from chapter_02_functions/01_exercises.ipynb
rename to 02_functions/01_exercises.ipynb
index 664e8f0..795be04 100644
--- a/chapter_02_functions/01_exercises.ipynb
+++ b/02_functions/01_exercises.ipynb
@@ -4,28 +4,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/01_exercises.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/01_exercises.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 2: Functions & Modularization"
+ "# Chapter 2: Functions & Modularization (Coding Exercises)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Coding Exercises"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The exercises below assume that you have read the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb) of Chapter 2.\n",
+ "The exercises below assume that you have read the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb) of Chapter 2.\n",
"\n",
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
]
@@ -34,7 +27,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Volume of a Sphere"
+ "## Volume of a Sphere"
]
},
{
@@ -45,7 +38,7 @@
"\n",
"Hints:\n",
"- use an appropriate approximation for $\\pi$\n",
- "- you may use the [standard library ](https://docs.python.org/3/library/index.html) to do so if you have already looked at the [second part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/02_content.ipynb) of Chapter 2."
+ "- you may use the [standard library ](https://docs.python.org/3/library/index.html) to do so if you have already looked at the [second part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/02_content.ipynb) of Chapter 2."
]
},
{
@@ -57,15 +50,6 @@
"import ... # you may drop this cell and use your own approximation for Pi"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "r = ..."
- ]
- },
{
"cell_type": "code",
"execution_count": null,
diff --git a/chapter_02_functions/02_content.ipynb b/02_functions/02_content.ipynb
similarity index 93%
rename from chapter_02_functions/02_content.ipynb
rename to 02_functions/02_content.ipynb
index 4c18bb4..06f1765 100644
--- a/chapter_02_functions/02_content.ipynb
+++ b/02_functions/02_content.ipynb
@@ -8,7 +8,7 @@
}
},
"source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/02_content.ipynb)."
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/02_content.ipynb)."
]
},
{
@@ -19,7 +19,7 @@
}
},
"source": [
- "# Chapter 2: Functions & Modularization (Part 2)"
+ "# Chapter 2: Functions & Modularization (continued)"
]
},
{
@@ -32,28 +32,8 @@
"source": [
"So far, we have only used what we refer to as **core** Python in this book. By this, we mean all the syntactical rules as specified in the [language reference ](https://docs.python.org/3/reference/) and a minimal set of about 50 built-in [functions ](https://docs.python.org/3/library/functions.html). With this, we could already implement any algorithm or business logic we can think of!\n",
"\n",
- "However, after our first couple of programs, we would already start seeing recurring patterns in the code we write. In other words, we would constantly be \"reinventing the wheel\" in each new project."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "slideshow": {
- "slide_type": "slide"
- }
- },
- "source": [
- "## Extending Core Python"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "slideshow": {
- "slide_type": "skip"
- }
- },
- "source": [
+ "However, after our first couple of programs, we would already start seeing recurring patterns in the code we write. In other words, we would constantly be \"reinventing the wheel\" in each new project.\n",
+ "\n",
"Would it not be smarter to pull out the reusable components from our programs and put them into some project independent **library** of generically useful functionalities? Then we would only need a way of including these **utilities** in our projects.\n",
"\n",
"As all programmers across all languages face this very same issue, most programming languages come with a so-called **[standard library ](https://en.wikipedia.org/wiki/Standard_library)** that provides utilities to accomplish everyday tasks without much code. Examples are making an HTTP request to some website, open and read popular file types (e.g., CSV or Excel files), do something on a computer's file system, and many more."
@@ -67,7 +47,7 @@
}
},
"source": [
- "### The Standard Library"
+ "## The Standard Library"
]
},
{
@@ -95,7 +75,7 @@
}
},
"source": [
- "#### [math ](https://docs.python.org/3/library/math.html) Module"
+ "### [math ](https://docs.python.org/3/library/math.html) Module"
]
},
{
@@ -448,7 +428,7 @@
"source": [
"Observe how the arguments passed to functions do not need to be just variables or simple literals. Instead, we may pass in any *expression* that evaluates to a *new* object of the type the function expects.\n",
"\n",
- "So just as a reminder from the expression vs. statement discussion in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/02_content.ipynb#Expressions): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is yet another operator. So both of the next two code cells are just expressions! They have no permanent side effects in memory. We may execute them as often as we want *without* changing the state of the program (i.e., this Jupyter notebook).\n",
+ "So just as a reminder from the expression vs. statement discussion in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb#Expressions): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is yet another operator. So both of the next two code cells are just expressions! They have no permanent side effects in memory. We may execute them as often as we want *without* changing the state of the program (i.e., this Jupyter notebook).\n",
"\n",
"So, regarding the very next cell in particular: Although the `2 ** 2` creates a *new* object `4` in memory that is then immediately passed into the [math.sqrt() ](https://docs.python.org/3/library/math.html#math.sqrt) function, once that function call returns, \"all is lost\" and the newly created `4` object is forgotten again, as well as the return value of [math.sqrt() ](https://docs.python.org/3/library/math.html#math.sqrt)."
]
@@ -570,7 +550,7 @@
}
},
"source": [
- "#### [random ](https://docs.python.org/3/library/random.html) Module"
+ "### [random ](https://docs.python.org/3/library/random.html) Module"
]
},
{
@@ -629,7 +609,7 @@
}
},
"source": [
- "Besides the usual dunder-style attributes, the built-in [dir() ](https://docs.python.org/3/library/functions.html#dir) function lists some attributes in an upper case naming convention and many others starting with a *single* underscore `_`. To understand the former, we must wait until [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb), while the latter is explained further below."
+ "Besides the usual dunder-style attributes, the built-in [dir() ](https://docs.python.org/3/library/functions.html#dir) function lists some attributes in an upper case naming convention and many others starting with a *single* underscore `_`. To understand the former, we must wait until [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb), while the latter is explained further below."
]
},
{
@@ -992,7 +972,7 @@
}
},
"source": [
- "### Third-party Packages"
+ "## Third-party Packages"
]
},
{
@@ -1020,7 +1000,7 @@
}
},
"source": [
- "#### [numpy](http://www.numpy.org/) Library"
+ "### [numpy](http://www.numpy.org/) Library"
]
},
{
@@ -1033,7 +1013,7 @@
"source": [
"[numpy](http://www.numpy.org/) is the de-facto standard in the Python world for handling **array-like** data. That is a fancy word for data that can be put into a matrix or vector format.\n",
"\n",
- "As [numpy](http://www.numpy.org/) is *not* in the [standard library ](https://docs.python.org/3/library/index.html), it must be *manually* installed, for example, with the [pip](https://pip.pypa.io/en/stable/) tool. As mentioned in [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/00_content.ipynb#Markdown-Cells-vs.-Code-Cells), to execute terminal commands from within a Jupyter notebook, we start a code cell with an exclamation mark.\n",
+ "As [numpy](http://www.numpy.org/) is *not* in the [standard library ](https://docs.python.org/3/library/index.html), it must be *manually* installed, for example, with the [pip](https://pip.pypa.io/en/stable/) tool. As mentioned in [Chapter 0 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/00_content.ipynb#Markdown-Cells-vs.-Code-Cells), to execute terminal commands from within a Jupyter notebook, we start a code cell with an exclamation mark.\n",
"\n",
"If you are running this notebook with an installation of the [Anaconda Distribution](https://www.anaconda.com/distribution/), then [numpy](http://www.numpy.org/) is probably already installed. Running the cell below confirms that."
]
@@ -1327,7 +1307,7 @@
}
},
"source": [
- "### Local Modules and Packages"
+ "## Local Modules and Packages"
]
},
{
@@ -1338,7 +1318,7 @@
}
},
"source": [
- "For sure, we can create local modules and packages. In the Chapter 2 directory, there is a [*sample_module.py* ](https://github.com/webartifex/intro-to-python/blob/develop/chapter_02_functions/sample_module.py) file that contains, among others, a function equivalent to the final version of `average_evens()`. To be realistic, this sample module is structured in a modular manner with several functions building on each other. It is best to skim over it *now* before reading on.\n",
+ "For sure, we can create local modules and packages. In the Chapter 2 directory, there is a [*sample_module.py* ](https://github.com/webartifex/intro-to-python/blob/develop/02_functions/sample_module.py) file that contains, among others, a function equivalent to the final version of `average_evens()`. To be realistic, this sample module is structured in a modular manner with several functions building on each other. It is best to skim over it *now* before reading on.\n",
"\n",
"To make code we put into a *.py* file available in our program, we import it as a module just as we did above with modules in the [standard library ](https://docs.python.org/3/library/index.html) or third-party packages.\n",
"\n",
@@ -1358,7 +1338,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/home/webartifex/repos/intro-to-python/chapter_02_functions\n"
+ "/home/webartifex/repos/intro-to-python/02_functions\n"
]
}
],
@@ -1404,7 +1384,7 @@
{
"data": {
"text/plain": [
- ""
+ ""
]
},
"execution_count": 41,
@@ -1424,7 +1404,7 @@
}
},
"source": [
- "Disregarding the dunder-style attributes, `mod` defines the attributes `_round_all`, `_scaled_average`, `average`, `average_evens`, and `average_odds`, which are exactly the ones we would expect from reading the [*sample_module.py* ](https://github.com/webartifex/intro-to-python/blob/develop/chapter_02_functions/sample_module.py) file.\n",
+ "Disregarding the dunder-style attributes, `mod` defines the attributes `_round_all`, `_scaled_average`, `average`, `average_evens`, and `average_odds`, which are exactly the ones we would expect from reading the [*sample_module.py* ](https://github.com/webartifex/intro-to-python/blob/develop/02_functions/sample_module.py) file.\n",
"\n",
"A convention when working with imported code is to *disregard* any attributes starting with a single underscore `_`. These are considered **private** and constitute **implementation details** the author of the imported code might change in a future version of his software. We *must not* rely on them in any way.\n",
"\n",
@@ -1475,7 +1455,7 @@
}
},
"source": [
- "We use the imported `mod.average_evens()` just like `average_evens()` defined in the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb) of this chapter. The advantage we get from **modularization** with *.py* files is that we can now easily reuse functions across different Jupyter notebooks without redefining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook."
+ "We use the imported `mod.average_evens()` just like `average_evens()` defined in the [first part ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb) of this chapter. The advantage we get from **modularization** with *.py* files is that we can now easily reuse functions across different Jupyter notebooks without redefining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook."
]
},
{
@@ -1591,7 +1571,7 @@
}
},
"source": [
- "Packages are a generalization of modules, and we look at one in detail in [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_11_classes/00_content.ipynb). You may, however, already look at a [sample package ](https://github.com/webartifex/intro-to-python/tree/develop/chapter_11_classes/sample_package) in the repository, which is nothing but a folder with *.py* files in it.\n",
+ "Packages are a generalization of modules, and we look at one in detail in [Chapter 11 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/11_classes/00_content.ipynb). You may, however, already look at a [sample package ](https://github.com/webartifex/intro-to-python/tree/develop/11_classes/sample_package) in the repository, which is nothing but a folder with *.py* files in it.\n",
"\n",
"As a further reading on modules and packages, we refer to the [official tutorial ](https://docs.python.org/3/tutorial/modules.html)."
]
diff --git a/chapter_02_functions/03_summary.ipynb b/02_functions/03_summary.ipynb
similarity index 93%
rename from chapter_02_functions/03_summary.ipynb
rename to 02_functions/03_summary.ipynb
index c5d712b..2161f17 100644
--- a/chapter_02_functions/03_summary.ipynb
+++ b/02_functions/03_summary.ipynb
@@ -8,18 +8,7 @@
}
},
"source": [
- "# Chapter 2: Functions & Modularization"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "slideshow": {
- "slide_type": "skip"
- }
- },
- "source": [
- "## TL;DR"
+ "# Chapter 2: Functions & Modularization (TL;DR)"
]
},
{
diff --git a/chapter_02_functions/04_review.ipynb b/02_functions/04_review.ipynb
similarity index 90%
rename from chapter_02_functions/04_review.ipynb
rename to 02_functions/04_review.ipynb
index daa9d88..a85dade 100644
--- a/chapter_02_functions/04_review.ipynb
+++ b/02_functions/04_review.ipynb
@@ -4,21 +4,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# Chapter 2: Functions & Modularization"
+ "# Chapter 2: Functions & Modularization (Review Questions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Content Review"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The questions below assume that you have read the [first ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb) and the [second ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/02_content.ipynb) part of Chapter 2.\n",
+ "The questions below assume that you have read the [first ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb) and the [second ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/02_content.ipynb) part of Chapter 2.\n",
"\n",
"Be concise in your answers! Most questions can be answered in *one* sentence."
]
@@ -27,7 +20,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Essay Questions "
+ "## Essay Questions "
]
},
{
@@ -132,7 +125,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### True / False Questions"
+ "## True / False Questions"
]
},
{
diff --git a/chapter_02_functions/sample_module.py b/02_functions/sample_module.py
similarity index 100%
rename from chapter_02_functions/sample_module.py
rename to 02_functions/sample_module.py
diff --git a/03_conditionals/00_content.ipynb b/03_conditionals/00_content.ipynb
new file mode 100644
index 0000000..5a6bc8e
--- /dev/null
+++ b/03_conditionals/00_content.ipynb
@@ -0,0 +1,2831 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/00_content.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "# Chapter 3: Conditionals & Exceptions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "We analyzed every aspect of the `average_evens()` function in [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb) except for the `if`-related parts. While it does what we expect it to, there is a whole lot more to learn by taking it apart. In particular, the `if` may occur within both a **statement** or an **expression**, analogous as to how a noun in a natural language can be the subject of *or* an object in a sentence. What is common to both usages is that it leads to code being executed for *parts* of the input only. It is a way of controlling the **flow of execution** in a program.\n",
+ "\n",
+ "After deconstructing `if` in the first part of this chapter, we take a close look at a similar concept, namely handling **exceptions**."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## Boolean Expressions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Any expression that is either true or not is called a **boolean expression**. It is such simple true-or-false observations about the world on which mathematicians, and originally philosophers, base their rules of reasoning: They are studied formally in the field of [propositional logic ](https://en.wikipedia.org/wiki/Propositional_calculus).\n",
+ "\n",
+ "A trivial example involves the equality operator `==` that evaluates to either `True` or `False` depending on its operands \"comparing equal\" or not."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 == 42"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 == 123"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "The `==` operator handles objects of *different* types: Because of that, it implements a notion of equality in line with how humans think of things being equal or not. After all, `42` and `42.0` are different $0$s and $1$s for a computer and other programming languages may say `False` here! Technically, this is yet another example of operator overloading."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 == 42.0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "There are, however, cases where the `==` operator seems to not work intuitively. [Chapter 5 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/05_numbers/00_content.ipynb#Imprecision) provides more insights into this \"bug.\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 == 42.000000000000001"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## The `bool` Type"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "`True` and `False` are built-in *objects* of type `bool`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "True"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "94478067031520"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "id(True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "bool"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "False"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "94478067031552"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "id(False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "bool"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(False)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Let's not confuse the boolean `False` with `None`, another built-in object! We saw the latter before in [Chapter 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb#Function-Definitions) as the *implicit* return value of a function without a `return` statement.\n",
+ "\n",
+ "We might think of `None` indicating a \"maybe\" or even an \"unknown\" answer; however, for Python, there are no \"maybe\" or \"unknown\" objects, as we see further below!\n",
+ "\n",
+ "Whereas `False` is of type `bool`, `None` is of type `NoneType`. So, they are unrelated! On the contrary, as both `True` and `False` are of the same type, we could call them \"siblings.\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "None"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "94478066920032"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "id(None)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "NoneType"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(None)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Singletons"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "`True`, `False`, and `None` have the property that they each exist in memory only *once*. Objects designed this way are so-called **singletons**. This **[design pattern ](https://en.wikipedia.org/wiki/Design_Patterns)** was originally developed to keep a program's memory usage at a minimum. It may only be employed in situations where we know that an object does *not* mutate its value (i.e., to reuse the bag analogy from [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb#Objects-vs.-Types-vs.-Values), no flipping of $0$s and $1$s in the bag is allowed). In languages \"closer\" to the memory like C, we would have to code this singleton logic ourselves, but Python has this built in for *some* types.\n",
+ "\n",
+ "We verify this with either the `is` operator or by comparing memory addresses."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = True\n",
+ "b = True\n",
+ "\n",
+ "a is b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "To contrast this, we create *two* `789` objects."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = 789\n",
+ "b = 789\n",
+ "\n",
+ "a is b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "So the following expression regards *four* objects in memory: *One* `list` object holding six references to *three* other objects."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[True, False, None, True, False, None]"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "[True, False, None, True, False, None]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## Relational Operators"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "The equality operator is only one of several **relational** (i.e., \"comparison\") **operators** who all evaluate to a `bool` object."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 == 123"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 != 123"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "The \"less than\" `<` or \"greater than\" `>` operators mean \"*strictly* less than\" or \"*strictly* greater than\" but may be combined with the equality operator into just `<=` and `>=`. This is a shortcut for using the logical `or` operator as described in the next section."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 < 123"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 <= 123"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 > 123"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "42 >= 123"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## Logical Operators"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Boolean expressions may be combined or negated with the **logical operators** `and`, `or`, and `not` to form new boolean expressions. This may be done repeatedly to obtain boolean expressions of arbitrary complexity.\n",
+ "\n",
+ "Their usage is similar to how the equivalent words are used in everyday English:\n",
+ "\n",
+ "- `and` evaluates to `True` if *both* operands evaluate to `True` and `False` otherwise,\n",
+ "- `or` evaluates to `True` if either one *or* both operands evaluate to `True` and `False` otherwise, and\n",
+ "- `not` evaluates to `True` if its *only* operand evaluates to `False` and vice versa."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "a = 42\n",
+ "b = 87"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Relational operators have **[higher precedence ](https://docs.python.org/3/reference/expressions.html#operator-precedence)** over logical operators. So the following expression means what we intuitively think it does."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a > 5 and b <= 100"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "However, sometimes, it is good to use *parentheses* around each operand for clarity."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(a > 5) and (b <= 100)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "This is especially so when several logical operators are combined."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a <= 5 or not b > 100"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(a <= 5) or not (b > 100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(a <= 5) or (not (b > 100)) # no need to \"over do\" it"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "For even better readability, some practitioners suggest to *never* use the `>` and `>=` operators (cf., [source](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html); note that the included example is written in [Java ](https://en.wikipedia.org/wiki/Java_%28programming_language%29) where `&&` means `and` and `||` means `or`).\n",
+ "\n",
+ "We may **chain** operators if the expressions that contain them are combined with the `and` operator. For example, the following two cells implement the same logic, where the second is a lot easier to read."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "5 < a and a < 87"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "5 < a < 87"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Truthy vs. Falsy"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "The operands of a logical operator do not need to be *boolean* expressions but may be *any* expression. If an operand does *not* evaluate to an object of type `bool`, Python automatically casts it as such. Then, Pythonistas say that the expression is evaluated in a boolean context.\n",
+ "\n",
+ "For example, any non-zero numeric object is cast as `True`. While this behavior allows writing more concise and thus more \"beautiful\" code, it may also be a source of confusion.\n",
+ "\n",
+ "So, `(a - 40)` is cast as `True` and then the overall expression evaluates to `True` as well."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "(a - 40) and (b < 100)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Whenever we are unsure how Python evaluates a non-boolean expression in a boolean context, the [bool() ](https://docs.python.org/3/library/functions.html#bool) built-in allows us to do it ourselves. [bool() ](https://docs.python.org/3/library/functions.html#bool), like [int() ](https://docs.python.org/3/library/functions.html#int), is yet another *constructor*."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(a - 40)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(a - 42)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Let's keep in mind that negative numbers also evaluate to `True`!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 34,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(a - 44)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "In a boolean context, `None` is cast as `False`! So, `None` is *not* a \"maybe\" answer but a \"no.\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 35,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(None)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Another good rule to know is that container types (e.g., `list`) evaluate to `False` whenever they are empty and `True` if they hold at least one element."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool([])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool([False])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "With `str` objects, the empty `\"\"` evaluates to `False`, and any other to `True`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(\"\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 39,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "bool(\"Lorem ipsum dolor sit amet.\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Pythonistas use the terms **truthy** or **falsy** to describe a non-boolean expression's behavior when evaluated in a boolean context."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "### Short-Circuiting"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "When evaluating expressions involving the `and` and `or` operators, Python follows the **[short-circuiting ](https://en.wikipedia.org/wiki/Short-circuit_evaluation)** strategy: Once it is clear what the overall truth value is, no more operands are evaluated, and the result is *immediately* returned.\n",
+ "\n",
+ "Also, if such expressions are evaluated in a non-boolean context, the result is returned as is and *not* cast as a `bool` type.\n",
+ "\n",
+ "The two rules can be summarized as:\n",
+ "\n",
+ "- `a or b`: If `a` is truthy, it is returned *without* evaluating `b`. Otherwise, `b` is evaluated *and* returned.\n",
+ "- `a and b`: If `a` is falsy, it is returned *without* evaluating `b`. Otherwise, `b` is evaluated *and* returned.\n",
+ "\n",
+ "The rules may also be chained or combined.\n",
+ "\n",
+ "Let's look at a couple of examples below. To visualize which operands are evaluated, we define a helper function `expr()` that prints out the only argument it is passed before returning it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def expr(arg):\n",
+ " \"\"\"Print and return the only argument.\"\"\"\n",
+ " print(\"Arg:\", arg)\n",
+ " return arg"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "With the `or` operator, the first truthy operand is returned."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "0 or 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 0\n",
+ "Arg: 1\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(0) or expr(1) # both operands are evaluated"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 1\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(1) or expr(2) # 2 is not evaluated"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "0 or 1 or 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 0\n",
+ "Arg: 1\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "1"
+ ]
+ },
+ "execution_count": 46,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(0) or expr(1) or expr(2) # 2 is not evaluated"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "If all operands are falsy, the last one is returned."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "False or [] or 0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: False\n",
+ "Arg: []\n",
+ "Arg: 0\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 48,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(False) or expr([]) or expr(0) # all operands are evaluated"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "With the `and` operator, the first falsy operand is returned."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "0 and 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 0\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(0) and expr(1) # 1 is not evaluated"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 51,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "1 and 0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 1\n",
+ "Arg: 0\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 52,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(1) and expr(0) # both operands are evaluated"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 53,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "1 and 0 and 2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 1\n",
+ "Arg: 0\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "0"
+ ]
+ },
+ "execution_count": 54,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(1) and expr(0) and expr(2) # 2 is not evaluated"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "If all operands are truthy, the last one is returned."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "1 and 2 and 3"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Arg: 1\n",
+ "Arg: 2\n",
+ "Arg: 3\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 56,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "expr(1) and expr(2) and expr(3)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "The crucial takeaway is that Python does *not* necessarily evaluate *all* operands and, therefore, our code should never rely on that assumption."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## The `if` Statement"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "To write useful programs, we need to control the flow of execution, for example, to react to user input. The logic by which a program follows the rules from the \"real world\" is referred to as **[business logic ](https://en.wikipedia.org/wiki/Business_logic)**.\n",
+ "\n",
+ "One language feature to do so is the `if` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement)). It consists of:\n",
+ "\n",
+ "- *one* mandatory `if`-clause,\n",
+ "- an *arbitrary* number of `elif`-clauses (i.e., \"else if\"), and\n",
+ "- an *optional* `else`-clause.\n",
+ "\n",
+ "The `if`- and `elif`-clauses each specify one *boolean* expression, also called **condition** here, while the `else`-clause serves as the \"catch everything else\" case.\n",
+ "\n",
+ "In contrast to our intuitive interpretation in natural languages, only the code in *one* of the alternatives, also called **branches**, is executed. To be precise, it is always the code in the first clause whose condition evaluates to `True`.\n",
+ "\n",
+ "In terms of syntax, the header lines end with a colon, and the code blocks are indented. Formally, any statement that is written across several lines is called a **[compound statement ](https://docs.python.org/3/reference/compound_stmts.html#compound-statements)**, the code blocks are called **suites** and belong to one header line, and the term **clause** refers to a header line and its suite as a whole. So far, we have seen three compound statements: `for`, `if`, and `def`. On the contrary, **[simple statements ](https://docs.python.org/3/reference/simple_stmts.html#simple-statements)**, for example, `=`, `del`, or `return`, are written on *one* line.\n",
+ "\n",
+ "As an example, let's write code that checks if a randomly drawn number is divisible by `2`, `3`, both, or none. The code should print out a customized message for each of the *four* cases."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import random"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### \"Wrong Logic\" Example: Is the number divisible by `2`, `3`, both, or none?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "It turns out that translating this task into code is not so trivial. Whereas the code below looks right, it is *incorrect*. The reason is that the order of the `if`-, `elif`-, and `else`-clauses matters."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 is divisible by 2 only\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "if number % 2 == 0:\n",
+ " print(number, \"is divisible by 2 only\")\n",
+ "elif number % 3 == 0:\n",
+ " print(number, \"is divisible by 3 only\")\n",
+ "elif number % 2 == 0 and number % 3 == 0:\n",
+ " print(number, \"is divisible by 2 and 3\")\n",
+ "else:\n",
+ " print(number, \"is divisible by neither 2 nor 3\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### \"Correct Logic\" Example: Is the number divisible by `2`, `3`, both, or none?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "As a number divisible by both `2` and `3` is always a special (i.e., narrower) case of a number being divisible by either `2` or `3` on their own, we must check for that condition first. The order of the two latter cases is not important as they are mutually exclusive. Below is a correct implementation of the program."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {
+ "code_folding": [],
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 is divisible by 2 and 3\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "if number % 3 == 0 and number % 2 == 0:\n",
+ " print(number, \"is divisible by 2 and 3\")\n",
+ "elif number % 3 == 0:\n",
+ " print(number, \"is divisible by 3 only\")\n",
+ "elif number % 2 == 0:\n",
+ " print(number, \"is divisible by 2 only\")\n",
+ "else:\n",
+ " print(number, \"is divisible by neither 2 nor 3\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### \"Concise Logic\" Example: Is the number divisible by `2`, `3`, both, or none?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "A minor improvement could be to replace `number % 3 == 0 and number % 2 == 0` with the conciser `number % 6 == 0`. However, this has no effect on the order that is still essential for the code's correctness."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 is divisible by 2 and 3\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "if number % 6 == 0:\n",
+ " print(number, \"is divisible by 2 and 3\")\n",
+ "elif number % 3 == 0:\n",
+ " print(number, \"is divisible by 3 only\")\n",
+ "elif number % 2 == 0:\n",
+ " print(number, \"is divisible by 2 only\")\n",
+ "else:\n",
+ " print(number, \"is divisible by neither 2 nor 3\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### Only the `if`-clause is mandatory"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Often, we only need a reduced form of the `if` statement.\n",
+ "\n",
+ "For example, below we **inject** code to print a message at random."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "You read this as often as you see heads when tossing a coin\n"
+ ]
+ }
+ ],
+ "source": [
+ "if random.random() > 0.5:\n",
+ " print(\"You read this as often as you see heads when tossing a coin\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### Common Use Case: A binary Choice"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "More often than not, we model a **binary choice**. Then, we only need to write an `if`- and an `else`-clause."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 is even\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "if number % 2 == 0:\n",
+ " print(number, \"is even\")\n",
+ "else:\n",
+ " print(number, \"is odd\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "To write the condition even conciser, we may take advantage of Python's implicit casting and leave out the `== 0`. However, then we *must* exchange the two suits! The `if`-clause below means \"If the `number` is odd\" in plain English. That is the opposite of the `if`-clause above."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 69,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 is even\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "if number % 2: # Note the opposite meaning!\n",
+ " print(number, \"is odd\")\n",
+ "else:\n",
+ " print(number, \"is even\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### \"Hard to read\" Example: Nesting `if` Statements"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "We may **nest** `if` statements to control the flow of execution in a more granular way. Every additional layer, however, makes the code *less* readable, in particular, if we have more than one line per code block.\n",
+ "\n",
+ "For example, the code cell below implements an [A/B Testing ](https://en.wikipedia.org/wiki/A/B_testing) strategy where half the time a \"complex\" message is shown to a \"user\" while in the remaining times an \"easy\" message is shown. To do so, the code first \"tosses a coin\" and then checks a randomly drawn `number`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 70,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 can be divided by 2 without a rest\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "# Coin is heads.\n",
+ "if random.random() > 0.5:\n",
+ " if number % 2 == 0:\n",
+ " print(number, \"can be divided by 2 without a rest\")\n",
+ " else:\n",
+ " print(number, \"divided by 2 results in a non-zero rest\")\n",
+ "# Coin is tails.\n",
+ "else:\n",
+ " if number % 2 == 0:\n",
+ " print(number, \"is even\")\n",
+ " else:\n",
+ " print(number, \"is odd\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "#### \"Easy to read\" Example: Flattening nested `if` Statements"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "A way to make this code more readable is to introduce **temporary variables** *in combination* with the `and` operator to **flatten** the branching logic. The `if` statement then reads almost like plain English. In contrast to many other languages, creating variables is a computationally *cheap* operation in Python (i.e., only a reference is created) and also helps to document the code *inline* with meaningful variable names.\n",
+ "\n",
+ "Flattening the logic *without* temporary variables could lead to *more* sub-expressions in the conditions be evaluated than necessary. Do you see why?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(789)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "6 can be divided by 2 without a rest\n"
+ ]
+ }
+ ],
+ "source": [
+ "number = random.choice(numbers)\n",
+ "\n",
+ "coin_is_heads = random.random() > 0.5\n",
+ "number_is_even = number % 2 == 0\n",
+ "\n",
+ "if coin_is_heads and number_is_even:\n",
+ " print(number, \"can be divided by 2 without a rest\")\n",
+ "elif coin_is_heads and not number_is_even:\n",
+ " print(number, \"divided by 2 results in a non-zero rest\")\n",
+ "elif not coin_is_heads and number_is_even:\n",
+ " print(number, \"is even\")\n",
+ "else:\n",
+ " print(number, \"is odd\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## The `if` Expression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "When an `if` statement assigns an object to a variable according to a true-or-false condition (i.e., a binary choice), there is a shortcut: We assign the variable the result of a so-called **[conditional expression ](https://docs.python.org/3/reference/expressions.html#conditional-expressions)**, or `if` expression for short, instead.\n",
+ "\n",
+ "Think of a situation where we evaluate a piece-wise functional relationship $y = f(x)$ at a given $x$, for example:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "$\n",
+ "y = f(x) =\n",
+ "\\begin{cases}\n",
+ "0, \\text{ if } x \\le 0 \\\\\n",
+ "x, \\text{ otherwise}\n",
+ "\\end{cases}\n",
+ "$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Of course, we could use an `if` statement as above to do the job. Yet, this is rather lengthy."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 74,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x = 3\n",
+ "\n",
+ "if x <= 0:\n",
+ " y = 0\n",
+ "else:\n",
+ " y = x\n",
+ "\n",
+ "y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "On the contrary, the `if` expression fits into one line. The main downside is a potential loss in readability, in particular, if the functional relationship is not that simple. Also, some practitioners do *not* like that the condition is in the middle of the expression."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 75,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x = 3\n",
+ "\n",
+ "y = 0 if x <= 0 else x\n",
+ "\n",
+ "y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "In this example, however, the most elegant solution is to use the built-in [max() ](https://docs.python.org/3/library/functions.html#max) function."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 76,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x = 3\n",
+ "\n",
+ "y = max(0, x)\n",
+ "\n",
+ "y"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "## The `try` Statement"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "In the previous two chapters, we encountered a couple of *runtime* errors. A natural urge we might have after reading about conditional statements is to write code that somehow reacts to the occurrence of such exceptions.\n",
+ "\n",
+ "Consider a situation where we are given some user input that may contain values that cause problems. To illustrate this, we draw a random integer between `0` and `5`, and then divide by this number. Naturally, we see a `ZeroDivisionError` in 16.6% of the cases."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(123)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "ename": "ZeroDivisionError",
+ "evalue": "division by zero",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0muser_input\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mchoice\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;36m1\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0muser_input\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
+ ]
+ }
+ ],
+ "source": [
+ "user_input = random.choice([0, 1, 2, 3, 4, 5])\n",
+ "\n",
+ "1 / user_input"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "With the compound `try` statement (cf., [reference ](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement)), we can **handle** any *runtime* error.\n",
+ "\n",
+ "In its simplest form, it comes with just two clauses: `try` and `except`. The following tells Python to execute the code in the `try`-clause, and if *anything* goes wrong, continue in the `except`-clause instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-clause is *not* executed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(123)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Something went wrong\n"
+ ]
+ }
+ ],
+ "source": [
+ "user_input = random.choice([0, 1, 2, 3, 4, 5])\n",
+ "\n",
+ "try:\n",
+ " print(\"The result is\", 1 / user_input)\n",
+ "except:\n",
+ " print(\"Something went wrong\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "However, it is good practice *not* to handle *any* possible exception but only the ones we may *expect* from the code in the `try`-clause. The reason for that is that we do not want to risk *suppressing* an exception that we do *not* expect. Also, the code base becomes easier to understand as we communicate what could go wrong during execution in an *explicit* way to the (human) reader. Python comes with a lot of [built-in exceptions ](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) that we should familiarize ourselves with.\n",
+ "\n",
+ "Another good practice is to always keep the code in the `try`-clause short to not *accidentally* handle an exception we do *not* want to handle.\n",
+ "\n",
+ "In the example, we are dividing numbers and may expect a `ZeroDivisionError`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 81,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(123)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Something went wrong\n"
+ ]
+ }
+ ],
+ "source": [
+ "user_input = random.choice([0, 1, 2, 3, 4, 5])\n",
+ "\n",
+ "try:\n",
+ " print(\"The result is\", 1 / user_input)\n",
+ "except ZeroDivisionError:\n",
+ " print(\"Something went wrong\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "Often, we may have to run some code *independent* of an exception occurring, for example, to close a connection to a database. To achieve that, we add a `finally`-clause to the `try` statement.\n",
+ "\n",
+ "Similarly, we may have to run some code *only if* no exception occurs, but we do not want to put it in the `try`-clause as per the good practice mentioned above. To achieve that, we add an `else`-clause to the `try` statement.\n",
+ "\n",
+ "To showcase everything together, we look at one last example. It is randomized: So, run the cell several times and see for yourself."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 83,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "random.seed(123)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 84,
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Oops. Division by 0. How does that work?\n",
+ "I am always printed\n"
+ ]
+ }
+ ],
+ "source": [
+ "user_input = random.choice([0, 1, 2, 3, 4, 5])\n",
+ "\n",
+ "try:\n",
+ " result = 1 / user_input\n",
+ "except ZeroDivisionError:\n",
+ " print(\"Oops. Division by 0. How does that work?\")\n",
+ "else:\n",
+ " print(\"The result is\", result)\n",
+ "finally:\n",
+ " print(\"I am always printed\")"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "livereveal": {
+ "auto_select": "code",
+ "auto_select_fragment": true,
+ "scroll": true,
+ "theme": "serif"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "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": "384px"
+ },
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/03_conditionals/01_exercises.ipynb b/03_conditionals/01_exercises.ipynb
new file mode 100644
index 0000000..513c67e
--- /dev/null
+++ b/03_conditionals/01_exercises.ipynb
@@ -0,0 +1,205 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/01_exercises.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 3: Conditionals & Exceptions (Coding Exercises)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The exercises below assume that you have read [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb).\n",
+ "\n",
+ "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Discounting Customer Orders"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q1**: Write a function `discounted_price()` that takes the positional arguments `unit_price` (of type `float`) and `quantity` (of type `int`) and implements a discount scheme for a line item in a customer order as follows:\n",
+ "\n",
+ "- if the unit price is over 100 dollars, grant 10% relative discount\n",
+ "- if a customer orders more than 10 items, one in every five items is for free\n",
+ "\n",
+ "Only one of the two discounts is granted, whichever is better for the customer.\n",
+ "\n",
+ "The function should then return the overall price for the line item. Do not forget to round appropriately."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def discounted_price(unit_price, quantity):\n",
+ " \"\"\"Calculate the price of a line item in an order.\n",
+ "\n",
+ " Args:\n",
+ " unit_price (float): price of one ordered item\n",
+ " quantity (int): number of items ordered\n",
+ "\n",
+ " Returns:\n",
+ " line_item_price (float)\n",
+ " \"\"\"\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ "\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ "\n",
+ " return ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q2**: Calculate the final price for the following line items of an order:\n",
+ "- $7$ smartphones @ $99.00$ USD\n",
+ "- $3$ workstations @ $999.00$ USD\n",
+ "- $19$ GPUs @ $879.95$ USD\n",
+ "- $14$ Raspberry Pis @ $35.00$ USD"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q3**: Calculate the last two line items with order quantities of $20$ and $15$. What do you observe?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "discounted_price(...)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q4**: Looking at the `if`-`else`-logic in the function, why do you think the four example line items in **Q2** were chosen as they were?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "sideBar": true,
+ "skip_h1_title": true,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/03_conditionals/02_exercises.ipynb b/03_conditionals/02_exercises.ipynb
new file mode 100644
index 0000000..432ca73
--- /dev/null
+++ b/03_conditionals/02_exercises.ipynb
@@ -0,0 +1,140 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/02_exercises.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 3: Conditionals & Exceptions (Coding Exercises)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The exercises below assume that you have read [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb).\n",
+ "\n",
+ "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Fizz Buzz"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The kids game [Fizz Buzz ](https://en.wikipedia.org/wiki/Fizz_buzz) is said to be often used in job interviews for entry-level positions. However, opinions vary as to how good of a test it is (cf., [source ](https://news.ycombinator.com/item?id=16446774)).\n",
+ "\n",
+ "In its simplest form, a group of people starts counting upwards in an alternating fashion. Whenever a number is divisible by $3$, the person must say \"Fizz\" instead of the number. The same holds for numbers divisible by $5$ when the person must say \"Buzz.\" If a number is divisible by both numbers, one must say \"FizzBuzz.\" Probably, this game would also make a good drinking game with the \"right\" beverages."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q1**: First, create a list `numbers` with the numbers from 1 through 100. You could type all numbers manually, but there is, of course, a smarter way. The built-in [range() ](https://docs.python.org/3/library/functions.html#func-range) may be useful here. Read how it works in the documentation. To make the output of [range() ](https://docs.python.org/3/library/functions.html#func-range) a `list` object, you have to wrap it with the [list() ](https://docs.python.org/3/library/functions.html#func-list) built-in (i.e., `list(range(...))`)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "numbers = ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q2**: Loop over the `numbers` list and *replace* numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n",
+ "\n",
+ "In [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb#Who-am-I?-And-how-many?), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n",
+ "\n",
+ "So in each iteration of the `for`-loop, you have to determine an `index` variable as well as check the actual `number` for its divisors.\n",
+ "\n",
+ "Hint: the order of the conditions is important!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in numbers:\n",
+ " ...\n",
+ "\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ...\n",
+ " ..."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q3**: Create a loop that prints out either the number or any of the Fizz Buzz substitutes in `numbers`! Do it in such a way that the output is concise!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "for number in numbers:\n",
+ " print(...)"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "sideBar": true,
+ "skip_h1_title": true,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/03_conditionals/03_summary.ipynb b/03_conditionals/03_summary.ipynb
new file mode 100644
index 0000000..86c8468
--- /dev/null
+++ b/03_conditionals/03_summary.ipynb
@@ -0,0 +1,76 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "# Chapter 3: Conditionals & Exceptions (TL;DR)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "skip"
+ }
+ },
+ "source": [
+ "- **boolean expressions** evaluate to either `True` or `False`\n",
+ "- **relational operators** (e.g., `==` or `!=`) compare operands according to \"human\" interpretations\n",
+ "- **logical operators** (e.g., `and` )combine boolean sub-expressions to more \"complex\" expressions\n",
+ "- the **conditional statement** (i.e., the `if` statement) allows **controlling** the **flow of execution** depending on some **conditions**\n",
+ "- a **conditional expression** is a short form of a conditional statement\n",
+ "- **exception handling** is also a common way of **controlling** the **flow of execution**, in particular, if we have to be prepared for bad input data"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "livereveal": {
+ "auto_select": "code",
+ "auto_select_fragment": true,
+ "scroll": true,
+ "theme": "serif"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "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": "384px"
+ },
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/03_conditionals/04_review.ipynb b/03_conditionals/04_review.ipynb
new file mode 100644
index 0000000..78d9061
--- /dev/null
+++ b/03_conditionals/04_review.ipynb
@@ -0,0 +1,201 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Chapter 3: Conditionals & Exceptions (Review Questions)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The questions below assume that you have read [Chapter 3 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb).\n",
+ "\n",
+ "Be concise in your answers! Most questions can be answered in *one* sentence."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Essay Questions "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q1**: What is the **singleton** design pattern? How many objects does the expression `[True, False, True, False]` generate in memory?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q2**: What do we mean when we talk about **truthy** and **falsy** expressions?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q3**: Describe in your own words the concept of **short-circuiting**! What does it imply for an individual sub-expression in a boolean expression?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q4**: Explain how the conceptual difference between a **statement** and an **expression** relates to the difference between a **conditional statement** and a **conditional expression**."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q5**: Why is the use of **temporary variables** encouraged in Python?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q6**: What does the `finally`-clause enforce in this code snippet? How can a `try` statement be useful *without* an `except`-clause?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```python\n",
+ "try:\n",
+ " print(\"Make a request to a service on the internet\")\n",
+ "finally:\n",
+ " print(\"This could be clean-up code\")\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## True / False Questions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Motivate your answer with *one short* sentence!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q7**: The objects `True`, `False`, and `None` represent the idea of *yes*, *no*, and *maybe* answers in a natural language.\n",
+ "\n",
+ "Hint: you also respond with a code cell."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Q8**: The `try` statement is useful for handling **syntax** errors."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ " < your answer >"
+ ]
+ }
+ ],
+ "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.8.6"
+ },
+ "toc": {
+ "base_numbering": 1,
+ "nav_menu": {},
+ "number_sections": false,
+ "sideBar": true,
+ "skip_h1_title": true,
+ "title_cell": "Table of Contents",
+ "title_sidebar": "Contents",
+ "toc_cell": false,
+ "toc_position": {},
+ "toc_section_display": false,
+ "toc_window_display": false
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/README.md b/README.md
index 35f4dbc..7328211 100644
--- a/README.md
+++ b/README.md
@@ -15,60 +15,78 @@ Alternatively, the content can be viewed in a web browser
or interactively (i.e., code can be executed) on [Binder ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab).
- *Chapter 0*: Introduction
- - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/00_content.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_00_intro/00_content.ipynb)
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/00_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/00_intro/00_content.ipynb)
(Python's History & Background;
Open-source & Communities;
JupyterLab;
Programming vs. Computer Science;
Learning Tips)
- - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/01_exercises.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_00_intro/01_exercises.ipynb)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/01_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/00_intro/01_exercises.ipynb)
(Mastering Markdown)
- - [review ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_00_intro/02_review.ipynb)
+ - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/00_intro/02_review.ipynb)
- **Part A: Expressing Logic**
- *Chapter 1*: Elements of a Program
- - [content 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/00_content.ipynb)
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/00_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/00_content.ipynb)
(A first Example: Averaging Even Numbers;
Operators;
Objects & Data Types;
Errors)
- - [exercises 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/01_exercises.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/01_exercises.ipynb)
- (Printing Output;
- Simple `for`-loops)
- - [content 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/02_content.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/02_content.ipynb)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/01_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/01_exercises.ipynb)
+ (Printing Output)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/02_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/02_exercises.ipynb)
+ (Simple `for`-loops)
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/03_content.ipynb)
(Memory in Detail;
Variables & References;
Mutability;
Expressions & Statements)
- - [exercises 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/03_exercises.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/03_exercises.ipynb)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/03_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/03_exercises.ipynb)
(Python as a Calculator)
- - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/04_summary.ipynb)
- - [review ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/05_review.ipynb)
- - [resources ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/06_resources.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/06_resources.ipynb)
+ - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/04_summary.ipynb)
+ - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/05_review.ipynb)
+ - [further resources ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/01_elements/06_resources.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/01_elements/06_resources.ipynb)
- *Chapter 2*: Functions & Modularization
- - [content 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/00_content.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/00_content.ipynb)
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/00_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/00_content.ipynb)
(Built-in Functions & Constructors;
Function Definitions;
Function Calls & Scoping Rules;
Positional vs. Keyword Arguments;
Modularization)
- - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/01_exercises.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/01_exercises.ipynb)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/01_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/01_exercises.ipynb)
(Volume of a Sphere)
- - [content 2 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/02_content.ipynb)
- [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_02_functions/02_content.ipynb)
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/02_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/02_functions/02_content.ipynb)
(Standard Library: `math` & `random` Modules;
Third-party Packages: `numpy` Library;
Writing one's own Modules)
- - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/03_summary.ipynb)
- - [review ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_02_functions/04_review.ipynb)
+ - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/03_summary.ipynb)
+ - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/02_functions/04_review.ipynb)
+ - *Chapter 3*: Conditionals & Exceptions
+ - [content ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/00_content.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/00_content.ipynb)
+ (Boolean Expressions;
+ Relational Operators;
+ Logical Operators;
+ `if` statement;
+ Exception Handling)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/01_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/01_exercises.ipynb)
+ (Discounting Customer Orders)
+ - [exercises ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/02_exercises.ipynb)
+ [](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/03_conditionals/02_exercises.ipynb)
+ (Fizz Buzz)
+ - [summary ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/03_summary.ipynb)
+ - [review questions ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/03_conditionals/04_review.ipynb)
#### Videos
@@ -204,10 +222,10 @@ The following instructions assume that
-The screeshot above shows how this project can be set up in an alternative way
+The screenshot above shows how this project can be set up in an alternative way
with the [zsh](https://en.wikipedia.org/wiki/Z_shell) CLI.
-First, the [git](https://git-scm.com/) tool is used
+First, [git](https://git-scm.com/) is used
to **clone** the course materials as a **repository**
into a new folder called "*intro-to-python*"
that lives under a "*repos*" folder.
@@ -216,7 +234,7 @@ First, the [git](https://git-scm.com/) tool is used
The `cd` command is used to "change directories".
-In the screenshot, the [pyenv](https://github.com/pyenv/pyenv) tool is used
+In the screenshot, [pyenv](https://github.com/pyenv/pyenv) is used
to set the project's Python version.
[pyenv](https://github.com/pyenv/pyenv)'s purpose is
to manage *many* parallel Python installations on the same computer.
@@ -225,7 +243,7 @@ It is highly recommended for professional users;
- `pyenv local ...`
-On the contrary, the [poetry](https://python-poetry.org/docs/) tool is used
+On the contrary, [poetry](https://python-poetry.org/docs/)'s purpose is
to manage third-party packages within the *same* Python installation
and, more importantly, on a per-project basis.
So, for example,
@@ -255,7 +273,7 @@ The following *one* command not only
[poetry](https://python-poetry.org/docs/) is also used
to execute commands in the project's (virtual) environment.
-The command is then prefixed with `poetry run ...`.
+To do that, the command is prefixed with `poetry run ...`.
The project uses [nox](https://nox.thea.codes/en/stable/)
to manage various maintenance tasks.
@@ -286,7 +304,8 @@ With that, the instructor can execute code in *presentation* mode during a class
However, the RISE extension does *not* work in the more recent
[JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) app
but only in the older [Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/stable/) app,
- which comes with less features and a simpler [GUI](https://en.wikipedia.org/wiki/Graphical_user_interface).
+ which comes with less features
+ and a simpler [GUI ](https://en.wikipedia.org/wiki/Graphical_user_interface).
The instructor can start the latter with:
- `poetry run jupyter notebook`
@@ -322,4 +341,5 @@ Alexander Hess is a PhD student
at the Chair of Logistics Management at [WHU - Otto Beisheim School of Management](https://www.whu.edu)
where he conducts research on urban delivery platforms
and teaches coding courses based on Python in the BSc and MBA programs.
-Connect him on [LinkedIn](https://www.linkedin.com/in/webartifex).
\ No newline at end of file
+
+Connect him on [LinkedIn](https://www.linkedin.com/in/webartifex).
diff --git a/chapter_01_elements/01_exercises.ipynb b/chapter_01_elements/01_exercises.ipynb
deleted file mode 100644
index 6e057b5..0000000
--- a/chapter_01_elements/01_exercises.ipynb
+++ /dev/null
@@ -1,336 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud ](https://mybinder.org/v2/gh/webartifex/intro-to-python/develop?urlpath=lab/tree/chapter_01_elements/01_exercises.ipynb)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Chapter 1: Elements of a Program"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Coding Exercises"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The exercises below assume that you have read the first part of [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb).\n",
- "\n",
- "The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### **Q1**: Printing Output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q1.1**: *Concatenate* `greeting` and `audience` below with the `+` operator and print out the resulting message `\"Hello World\"` with only *one* call of the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function!\n",
- "\n",
- "Hint: You may have to \"add\" a space character in between `greeting` and `audience`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "greeting = \"Hello\"\n",
- "audience = \"World\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q1.2**: How is your answer to **Q1.1** an example of the concept of **operator overloading**?"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- " < your answer >"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q1.3**: Read the documentation on the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function! How can you print the above message *without* concatenating `greeting` and `audience` first in *one* call of [print() ](https://docs.python.org/3/library/functions.html#print)?\n",
- "\n",
- "Hint: The `*objects` in the documentation implies that we can put several *expressions* (i.e., variables) separated by commas within the same call of the [print() ](https://docs.python.org/3/library/functions.html#print) function."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q1.4**: What does the `sep=\" \"` mean in the documentation on the built-in [print() ](https://docs.python.org/3/library/functions.html#print) function? Adjust and use it to print out the three names referenced by `first`, `second`, and `third` on *one* line separated by *commas* with only *one* call of the [print() ](https://docs.python.org/3/library/functions.html#print) function!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "first = \"Anthony\"\n",
- "second = \"Berta\"\n",
- "third = \"Christian\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q1.5**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Adjust and use it within the `for`-loop to print the numbers `1` through `10` on *one* line with only *one* call of the [print() ](https://docs.python.org/3/library/functions.html#print) function!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### **Q2**: Simple `for`-loops"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`for`-loops are extremely versatile in Python. That is different from many other programming languages.\n",
- "\n",
- "As shown in the first example in [Chapter 1 ](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/develop/chapter_01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q2.1**: Fill in the *condition* of the `if` statement such that only numbers divisible by `3` are printed! Adjust the call of the [print() ](https://docs.python.org/3/library/functions.html#print) function such that the `for`-loop prints out all the numbers on *one* line of output!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in numbers:\n",
- " if ...:\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Instead of looping over an *existing* object referenced by a variable like `numbers`, we may also create a *new* object within the `for` statement and loop over it directly. For example, below we write out the `list` object as a *literal*.\n",
- "\n",
- "Generically, the objects contained in a `list` objects are referred to as its **elements**. We reflect that in the name of the *target* variable `element` that is assigned a different number in every iteration of the `for`-loop. While we could use *any* syntactically valid name, it is best to choose one that makes sense in the context (e.g., `number` in `numbers`).\n",
- "\n",
- "**Q2.2**: Fill in the condition of the `if` statement such that only numbers consisting of *one* digit are printed out! As before, print out all the numbers on *one* line of output!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for element in [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]:\n",
- " if ...:\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "An easy way to loop over a `list` object in a sorted manner, is to wrap it with the built-in [sorted() ](https://docs.python.org/3/library/functions.html#sorted) function.\n",
- "\n",
- "**Q2.3**: Fill in the condition of the `if` statement such that only odd numbers are printed out! Put all the numbers on *one* line of output!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in sorted(numbers):\n",
- " if ...:\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Whenever we want to loop over numbers representing a [series ](https://en.wikipedia.org/wiki/Series_%28mathematics%29) in the mathematical sense (i.e., a rule to calculate the next number from its predecessor), we may be able to use the [range() ](https://docs.python.org/3/library/functions.html#func-range) built-in.\n",
- "\n",
- "For example, to loop over the whole numbers from `0` to `9` (both including) in order, we could write them out in a `list` like below.\n",
- "\n",
- "**Q2.4**: Fill in the call to the [print() ](https://docs.python.org/3/library/functions.html#print) function such that all the numbers are printed on *one* line ouf output!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q2.5**: Read the documentation on the [range() ](https://docs.python.org/3/library/functions.html#func-range) built-in! It may be used with either one, two, or three expressions \"passed\" in. What do `start`, `stop`, and `step` mean? Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to mimic the output of **Q2.4**!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in range(...):\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q2.6**: Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to print out *all* numbers from `1` to `10` (both including)!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in range(...):\n",
- " print(...)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**Q2.7**: Fill in the calls to [range() ](https://docs.python.org/3/library/functions.html#func-range) and [print() ](https://docs.python.org/3/library/functions.html#print) to print out the *even* numbers from `1` to `10` (both including)! Do *not* use an `if` statement to accomplish this!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "for number in range(...):\n",
- " print(...)"
- ]
- }
- ],
- "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.8.6"
- },
- "toc": {
- "base_numbering": 1,
- "nav_menu": {},
- "number_sections": false,
- "sideBar": true,
- "skip_h1_title": true,
- "title_cell": "Table of Contents",
- "title_sidebar": "Contents",
- "toc_cell": false,
- "toc_position": {},
- "toc_section_display": false,
- "toc_window_display": false
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}
diff --git a/poetry.lock b/poetry.lock
index 9da7a06..9f17fc7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -555,7 +555,7 @@ webpdf = ["pyppeteer (0.2.2)"]
[[package]]
name = "nbformat"
-version = "5.0.7"
+version = "5.0.8"
description = "The Jupyter Notebook format"
category = "main"
optional = false
@@ -568,7 +568,8 @@ jupyter-core = "*"
traitlets = ">=4.1"
[package.extras]
-test = ["pytest", "pytest-cov", "testpath"]
+fast = ["fastjsonschema"]
+test = ["fastjsonschema", "testpath", "pytest", "pytest-cov"]
[[package]]
name = "nest-asyncio"
@@ -905,7 +906,7 @@ python-versions = ">= 3.5"
[[package]]
name = "traitlets"
-version = "5.0.4"
+version = "5.0.5"
description = "Traitlets Python configuration system"
category = "main"
optional = false
@@ -932,7 +933,7 @@ socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[[package]]
name = "virtualenv"
-version = "20.0.34"
+version = "20.0.35"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
@@ -1248,8 +1249,8 @@ nbconvert = [
{file = "nbconvert-6.0.7.tar.gz", hash = "sha256:cbbc13a86dfbd4d1b5dee106539de0795b4db156c894c2c5dc382062bbc29002"},
]
nbformat = [
- {file = "nbformat-5.0.7-py3-none-any.whl", hash = "sha256:ea55c9b817855e2dfcd3f66d74857342612a60b1f09653440f4a5845e6e3523f"},
- {file = "nbformat-5.0.7.tar.gz", hash = "sha256:54d4d6354835a936bad7e8182dcd003ca3dc0cedfee5a306090e04854343b340"},
+ {file = "nbformat-5.0.8-py3-none-any.whl", hash = "sha256:aa9450c16d29286dc69b92ea4913c1bffe86488f90184445996ccc03a2f60382"},
+ {file = "nbformat-5.0.8.tar.gz", hash = "sha256:f545b22138865bfbcc6b1ffe89ed5a2b8e2dc5d4fe876f2ca60d8e6f702a30f8"},
]
nest-asyncio = [
{file = "nest_asyncio-1.4.1-py3-none-any.whl", hash = "sha256:a4487c4f49f2d11a7bb89a512a6886b6a5045f47097f49815b2851aaa8599cf0"},
@@ -1462,16 +1463,16 @@ tornado = [
{file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"},
]
traitlets = [
- {file = "traitlets-5.0.4-py3-none-any.whl", hash = "sha256:9664ec0c526e48e7b47b7d14cd6b252efa03e0129011de0a9c1d70315d4309c3"},
- {file = "traitlets-5.0.4.tar.gz", hash = "sha256:86c9351f94f95de9db8a04ad8e892da299a088a64fd283f9f6f18770ae5eae1b"},
+ {file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"},
+ {file = "traitlets-5.0.5.tar.gz", hash = "sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396"},
]
urllib3 = [
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
]
virtualenv = [
- {file = "virtualenv-20.0.34-py2.py3-none-any.whl", hash = "sha256:4ecd607e7809bd7384039065639a8babc9fa562fe1b73b24095ce85b83d55fcf"},
- {file = "virtualenv-20.0.34.tar.gz", hash = "sha256:4bf0e2bf99d33b123a895a5a244f0d7adb2a92171c6bbb31c3e2db235624abf1"},
+ {file = "virtualenv-20.0.35-py2.py3-none-any.whl", hash = "sha256:0ebc633426d7468664067309842c81edab11ae97fcaf27e8ad7f5748c89b431b"},
+ {file = "virtualenv-20.0.35.tar.gz", hash = "sha256:2a72c80fa2ad8f4e2985c06e6fc12c3d60d060e410572f553c90619b0f6efaf3"},
]
wcwidth = [
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},