Streamline previous content
This commit is contained in:
parent
84e08d06f4
commit
250aa09209
7 changed files with 181 additions and 104 deletions
|
@ -18,7 +18,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Read Chapter 0 of the book. Then work through the ten review questions."
|
||||
"Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up.ipynb) of the book. Then work through the ten review questions."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"\n",
|
||||
"It is intuitively best to take the very mindset of a small child when learing a foreign language and we do so for learning the Python language as well. This first chapter introduces simplistic examples and we better just accept them as they are without knowing any of the \"grammar\" rules yet. Then, we analyze them in parts and slowly build up our understanding.\n",
|
||||
"\n",
|
||||
"Consequently, if parts of this chapter do not make sense right away, let's not worry too much. Besides introducing some basics (that we need to understand), it also serves as an outlook for what is to come. So, many terms and concepts referenced here will be covered in great detail in following chapters."
|
||||
"Consequently, if parts of this chapter do not make sense right away, let's not worry too much. Besides introducing some basics that we need to understand, it also serves as an outlook for what is to come. So, many terms and concepts used here will be covered in great detail in following chapters."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"As our introductory example, we want to calculate the average of all even numbers from one through ten.\n",
|
||||
"As our introductory example, we want to calculate the *average* of all *even* numbers from *one* through *ten*.\n",
|
||||
"\n",
|
||||
"While we could come up with an [analytical solution](https://math.stackexchange.com/questions/935405/what-s-the-difference-between-analytical-and-numerical-approaches-to-problems/935446#935446) (i.e., derive some equation with \"pen and paper\" from, e.g., one of [Faulhaber's formulas](https://en.wikipedia.org/wiki/Faulhaber%27s_formula)), we instead solve the task programmatically.\n",
|
||||
"\n",
|
||||
|
@ -75,7 +75,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To verify that something happened in our computer's memory, we simply **reference** `numbers` and observe that Python indeed knows about."
|
||||
"To verify that something happened in our computer's memory, we simply **reference** `numbers` and observe that Python indeed knows about it."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -110,17 +110,17 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"So far, so good. Let's see how the desired result could be expressed as a **sequence of instructions** in Python.\n",
|
||||
"So far, so good. Let's see how the desired **computation** could be expressed as a **sequence of instructions** in Python.\n",
|
||||
"\n",
|
||||
"Intuitively, the line `for number in numbers` describes a \"loop\" over all the numbers in the `numbers` list, one at a time.\n",
|
||||
"\n",
|
||||
"The `if number % 2 == 0` may look disturbing at first sight. Both the `%` and `==` must have an unintuitive meaning here. Luckily, the **comment** in the same line after the `#` symbol has the answer: The program only does something if the current `number` is even.\n",
|
||||
"\n",
|
||||
"In particular, it increases `count` by $1$ and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` were initially set to $0$ and the single `=` reads as \"... is *set* equal to ...\". It could not indicate a mathematical equation as, for example, `count` is generally not equal to `count + 1`.\n",
|
||||
"In particular, it increases `count` by $1$ and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` were initially set to $0$ and the single `=` symbol reads as \"... is *set* equal to ...\". It could not indicate a mathematical equation as, for example, `count` is generally not equal to `count + 1`.\n",
|
||||
"\n",
|
||||
"Lastly, the `average` is calculated as the ratio of the final **values** of `total` and `count`. Overall, we divide the sum of all even numbers by the count of all even numbers, which is exactly what we are looking for.\n",
|
||||
"\n",
|
||||
"We also observe how the lines of code \"within\" the `for` and `if` **statements** are *indented* and *aligned* with multiples of **four spaces**: This shows immediately how the lines relate to each other."
|
||||
"We also observe how the lines of code \"within\" the `for` and `if` **statements** are **indented** and *aligned* with multiples of **four spaces**: This shows immediately how the lines relate to each other."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -200,7 +200,7 @@
|
|||
"source": [
|
||||
"Note how only two of the previous four code cells generate an **output** while two remained \"silent\" (i.e., there is no \"**Out[...]**\" after running the cell).\n",
|
||||
"\n",
|
||||
"By default, Jupyter notebooks show the value of a cell's last so-called **expression**. This output can be suppressed by ending the last line with a semicolon `;`."
|
||||
"By default, Jupyter notebooks show the value of a cell's last **expression**. This output can be suppressed by ending the last line with a semicolon `;`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -249,7 +249,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To visualize something before the end of the cell, we can use the [print()](https://docs.python.org/3/library/functions.html#print) built-in **function**."
|
||||
"To visualize something before the end of the cell, we use the [print()](https://docs.python.org/3/library/functions.html#print) built-in **function**."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -327,11 +327,13 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Python comes with basic mathematical operators built in. **[Operators](https://docs.python.org/3/reference/lexical_analysis.html#operators)** are built-in **tokens** that have a special meaning to the Python interpreter. Most operators either \"operate\" with the object immediately following them (= **unary** operators; e.g., negation) or somehow \"process\" the two objects \"around\" them (= **binary** operators; e.g., addition). But we will see some exceptions from that as well.\n",
|
||||
"Python comes with many **[operators](https://docs.python.org/3/reference/lexical_analysis.html#operators)** built in: They are **tokens** (i.e., \"symbols\") that have a special meaning to the Python interpreter.\n",
|
||||
"\n",
|
||||
"By definition, operators have **no** permanent **side effects** in the computer's memory. Although the code cells in this section do indeed lead to *new* objects being created in memory, they are immediately \"forgotten\" as they are not stored in a **variable** (like `numbers` above). We will revisit this idea further below when we compare **expressions** with **statements**.\n",
|
||||
"The arithmetic operators either \"operate\" with the number immediately following them (= **unary** operators; e.g., negation) or \"process\" the two numbers \"around\" them (= **binary** operators; e.g., addition). But we will see many exceptions from that as well.\n",
|
||||
"\n",
|
||||
"Let's see some examples of operators. We start with the binary `+` and the `-` operators for addition and subtraction. Binary operators resemble what mathematicians call [infix notation](https://en.wikipedia.org/wiki/Infix_notation) and have the expected meaning."
|
||||
"By definition, operators have **no** permanent **side effects** in the computer's memory. Although the code cells in this section do indeed create *new* numbers in memory (e.g., `77 + 13` creates `90`), they are immediately \"forgotten\" as they are not stored in a **variable** like `numbers` or `average` above. We will continue this thought further below when we compare **expressions** with **statements**.\n",
|
||||
"\n",
|
||||
"Let's see some examples of operators. We start with the binary `+` and the `-` operators for addition and subtraction. Binary operators are designed to resemble what mathematicians call [infix notation](https://en.wikipedia.org/wiki/Infix_notation) and have the expected meaning."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -425,7 +427,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"When we compare the output of the `*` and `/` operators for multiplication and division, we note the subtle difference between the $42$ and the $42.0$. This is a first illustration of the concept of a **data type**."
|
||||
"When we compare the output of the `*` and `/` operators for multiplication and division, we note the subtle *difference* between the $42$ and the $42.0$. This is a first illustration of the concept of a **data type**."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -543,7 +545,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To obtain the remainder of a division, we can use the **modulo operator** `%`."
|
||||
"To obtain the remainder of a division, we use the **modulo operator** `%`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -613,7 +615,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Modulo division can be useful if we, for example, need to get the last couple of digits of a large integer."
|
||||
"Modulo division is also useful if we, for example, need to get the last couple of digits of a large integer."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -672,7 +674,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The [divmod()](https://docs.python.org/3/library/functions.html#divmod) built-in function combines the integer and modulo divisions into one operation. However, this is not an operator any more (but a function). Also observe that [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers."
|
||||
"The [divmod()](https://docs.python.org/3/library/functions.html#divmod) built-in function combines the integer and modulo divisions into one operation. However, this is not an operator but a function. Also observe that [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -707,7 +709,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Raising a number to a power is performed with the **exponentiation operator** `**`. Note that this is different from the `^` operator many other programming languages might use and that also exists in Python with a *different* meaning."
|
||||
"Raising a number to a power is performed with the **exponentiation operator** `**`. This is different from the `^` operator many other programming languages use and that also exists in Python with a *different* meaning."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -742,7 +744,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The normal [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., \"PEMDAS\" rule) but parentheses help avoid confusion."
|
||||
"The normal [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., \"PEMDAS\" rule)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -777,7 +779,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The parentheses here serve as a **delimiter**."
|
||||
"Parentheses help avoid confusion and take the role of a **delimiter** here."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -871,7 +873,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"There are plenty more mathematical and non-mathematical operators that are introduced throughout this book together with the concepts they implement or support. Some of these are already shown in the next section."
|
||||
"There are many more non-mathematical operators that are introduced throughout this book together with the concepts they implement. Some of these are already shown in the next section."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -949,7 +951,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"139940106427216"
|
||||
"140658972730512"
|
||||
]
|
||||
},
|
||||
"execution_count": 27,
|
||||
|
@ -973,7 +975,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"139940106602344"
|
||||
"140658972907392"
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
|
@ -997,7 +999,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"139940105769456"
|
||||
"140658972586992"
|
||||
]
|
||||
},
|
||||
"execution_count": 29,
|
||||
|
@ -1017,7 +1019,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"These addresses are really not that meaningful for anything other than checking if two variables actually **point** at the same object. This may be helpful as different objects can of course have the same value."
|
||||
"These addresses are really not that meaningful for anything other than checking if two variables actually **point** at the same object. This may be helpful as, for example, different objects in memory may of course have the same value."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1041,7 +1043,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"`a` and `d` indeed have the same value as can be checked with the **equality operator** `==`. The resulting `True` (and the `False` below) is yet another data type, a so-called **boolean**. We will look into that closely in Chapter 3."
|
||||
"`a` and `d` indeed have the same value as can be checked with the **equality operator** `==`. The resulting `True` (and the `False` below) is yet another data type, a so-called **boolean**. We will look into that closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1780,7 +1782,7 @@
|
|||
" "
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f46584be518>"
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7fedb8113c50>"
|
||||
]
|
||||
},
|
||||
"execution_count": 50,
|
||||
|
@ -1801,7 +1803,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"For example, while the above code to calculate the average of the even numbers from 1 through 10 is correct, a Pythonista would re-write it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") built-in functions (cf., Chapter 2) as well as a so-called **list comprehension** (cf., Chapter 7). 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 from 1 through 10 is correct, a Pythonista would re-write it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") built-in functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) as well as a so-called **list comprehension** (cf., Chapter 7). Pythonic code runs faster in many cases and is less error prone."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2003,7 +2005,7 @@
|
|||
"\n",
|
||||
"At the same time, for a beginner's course it is often easier to just code in a linear fashion.\n",
|
||||
"\n",
|
||||
"In real data science projects one would probably employ a mixed approach and put re-usable code into so-called Python modules (i.e., *.py* files; cf., Chapter 2) and then use Jupyter notebooks to built up a linear report or story line for a business argument to be made."
|
||||
"In real data science projects one would probably employ a mixed approach and put re-usable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) and then use Jupyter notebooks to built up a linear report or story line for a business argument to be made."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2868,7 +2870,7 @@
|
|||
"\n",
|
||||
"In general, the assignment statement creates (or overwrites) a variable and makes it point to whatever object is on the right-hand side *only if* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it mutates some already existing object. And we always have to expect that the latter might have more than one variable pointing at it.\n",
|
||||
"\n",
|
||||
"In the beginning, visualizing the memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Adel%20x,%20y%0Ax%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x.copy%28%29%0Ax%5B0%5D%20%3D%2099&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) will assist in understanding what is going on."
|
||||
"Visualizing what is going on in the memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) might be helpful for a beginner."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2903,7 +2905,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Variable names may contain upper and lower case letters, numbers, and underscores (\"\\_\") and be as long as we want them to be. However, they must not begin with a number. Also, they must not be any of Python's **[keywords](https://docs.python.org/3/reference/lexical_analysis.html#keywords)**.\n",
|
||||
"Variable names may contain upper and lower case letters, numbers, and underscores (\"\\_\") and be as long as we want them to be. However, they must not begin with a number. Also, they must not be any of Python's built-in **[keywords](https://docs.python.org/3/reference/lexical_analysis.html#keywords)**.\n",
|
||||
"\n",
|
||||
"Variable names are usually chosen such that they do not need any more documentation and are self-explanatory. A very common convention is to use so-called **[snake\\_case](https://en.wikipedia.org/wiki/Snake_case)**: Keep everything lowercase and use underscores to seperate words.\n",
|
||||
"\n",
|
||||
|
@ -3150,7 +3152,7 @@
|
|||
" "
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f465852de48>"
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7fedb808c518>"
|
||||
]
|
||||
},
|
||||
"execution_count": 93,
|
||||
|
@ -3188,7 +3190,7 @@
|
|||
"\n",
|
||||
"What we said about individual operators above, namely that they have *no* side effects, should have been put here to begin with. The examples in the section on operators above were actually all expressions!\n",
|
||||
"\n",
|
||||
"The simplest possible expression contains only one variable (or literal)."
|
||||
"The simplest possible expressions contain only one variable or literal."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -3218,6 +3220,33 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 95,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"42"
|
||||
]
|
||||
},
|
||||
"execution_count": 95,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"42"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"For sure, we need to include operators to achieve something useful."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 96,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3230,7 +3259,7 @@
|
|||
"165"
|
||||
]
|
||||
},
|
||||
"execution_count": 95,
|
||||
"execution_count": 96,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3247,12 +3276,12 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The definition of an expression is **recursive**. So here the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression."
|
||||
"The definition of an expression is **recursive**. So, here the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 96,
|
||||
"execution_count": 97,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3265,7 +3294,7 @@
|
|||
"4492125"
|
||||
]
|
||||
},
|
||||
"execution_count": 96,
|
||||
"execution_count": 97,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3282,12 +3311,12 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Here, the variable `y` is combined with the literal `2` by the indexing operator `[]`. The resulting expression evaluates to the "
|
||||
"Here, the variable `y` is combined with the literal `2` by the indexing operator `[]`. The resulting expression evaluates to the third element in the `y` list."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 97,
|
||||
"execution_count": 98,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3300,7 +3329,7 @@
|
|||
"3"
|
||||
]
|
||||
},
|
||||
"execution_count": 97,
|
||||
"execution_count": 98,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3317,12 +3346,12 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"When not used as a **delimiter**, parentheses also constitute an operator, namely the **call operator** `()`. We have seen this syntax above when we \"called\" (i.e., executed) built-in functions and methods."
|
||||
"When not used as a delimiter, parentheses also constitute an operator, namely the **call operator** `()`. We have seen this syntax above when we \"called\" (i.e., executed) built-in functions and methods."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 98,
|
||||
"execution_count": 99,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3335,7 +3364,7 @@
|
|||
"104"
|
||||
]
|
||||
},
|
||||
"execution_count": 98,
|
||||
"execution_count": 99,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3368,7 +3397,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 99,
|
||||
"execution_count": 100,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "slide"
|
||||
|
@ -3382,7 +3411,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 100,
|
||||
"execution_count": 101,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "fragment"
|
||||
|
@ -3395,7 +3424,7 @@
|
|||
"'Hi class'"
|
||||
]
|
||||
},
|
||||
"execution_count": 100,
|
||||
"execution_count": 101,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3417,7 +3446,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 101,
|
||||
"execution_count": 102,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "fragment"
|
||||
|
@ -3430,7 +3459,7 @@
|
|||
"'Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi Hi '"
|
||||
]
|
||||
},
|
||||
"execution_count": 101,
|
||||
"execution_count": 102,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
|
@ -3458,14 +3487,14 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that changes the state of the program's memory or has some other side effect. Statements do not just evaluate to a value like expressions; instead, they create or change values.\n",
|
||||
"A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that changes the state of a program or has some other side effect. Statements do not just evaluate to a value like expressions; instead, they create or change values.\n",
|
||||
"\n",
|
||||
"Most notably of course are the `=` and `del` statements."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 102,
|
||||
"execution_count": 103,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "slide"
|
||||
|
@ -3478,7 +3507,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 103,
|
||||
"execution_count": 104,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3497,12 +3526,12 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The [print()](https://docs.python.org/3/library/functions.html#print) function is regarded a \"statement\" as well. In fact, it used to be a real statement in Python 2 and has all the necessary properties. It is a bit of a corner case as expressions are also \"printed\" in a Jupyter notebook when evaluated last in a code cell."
|
||||
"The built-in [print()](https://docs.python.org/3/library/functions.html#print) function is regarded a \"statement\" as well. In fact, it used to be a real statement in Python 2 and has all the necessary properties. It is a bit of a corner case as expressions are also \"printed\" in a Jupyter notebook when evaluated last in a code cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 104,
|
||||
"execution_count": 105,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "skip"
|
||||
|
@ -3549,7 +3578,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 105,
|
||||
"execution_count": 106,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "slide"
|
||||
|
@ -3577,7 +3606,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 106,
|
||||
"execution_count": 107,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "fragment"
|
||||
|
@ -3590,7 +3619,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 107,
|
||||
"execution_count": 108,
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "-"
|
||||
|
@ -3690,14 +3719,14 @@
|
|||
" - ignored by Python\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- functions (cf., Chapter 2)\n",
|
||||
"- functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.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",
|
||||
"\n",
|
||||
"\n",
|
||||
"- flow control (cf., Chapter 3)\n",
|
||||
" - expression of **logic** or an **algorithm**\n",
|
||||
"- flow control (cf., [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb))\n",
|
||||
" - expression of **business logic** or an **algorithm**\n",
|
||||
" - conditional execution of a small **branch** within a program (i.e., `if` statements)\n",
|
||||
" - repetitive execution of parts of a program (i.e., `for`-loops and `while`-loops)"
|
||||
]
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Read Chapter 1 of the book. Then work through the ten review questions."
|
||||
"Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) of the book. Then work through the ten review questions."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"In Chapter 1 we typed the **business logic** of our little program to calculate the mean of a subset of a list of numbers right into the code cells. Then, we executed them one after another. We had no way of **re-using** the code except for either re-executing the cells or copying and pasting their contents into other cells. 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/master/01_elements.ipynb) we typed the **business logic** of our little program to calculate the mean of a subset of a list of numbers right into the code cells. Then, we executed them one after another. We had no way of **re-using** the code except for either re-executing the cells or copying and pasting their contents into other cells. 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",
|
||||
"At the same time, we executed built-in functions (e.g., [print()](https://docs.python.org/3/library/functions.html#print), [sum()](https://docs.python.org/3/library/functions.html#sum), [len()](https://docs.python.org/3/library/functions.html#len), [id()](https://docs.python.org/3/library/functions.html#id), or [type()](https://docs.python.org/3/library/functions.html#type)) that obviously must be re-using the same parts inside core Python every time we use them.\n",
|
||||
"\n",
|
||||
|
@ -45,7 +45,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** can be created with the `def` statement. To extend an already familiar example, we re-use the introductory example from Chapter 1 in its final Pythonic version and transform it into the function `average_evens()` below. \n",
|
||||
"So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** can be created with the `def` statement. To extend an already familiar example, we re-use the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) in its final Pythonic version and transform it into the function `average_evens()` below. \n",
|
||||
"\n",
|
||||
"A function's **name** must be chosen according to the same naming rules as for ordinary variables. In fact, Python manages function names just 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 actually part of the name but must always be written out in the `def` statement for syntactic reasons.\n",
|
||||
"\n",
|
||||
|
@ -142,7 +142,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"139655430681056"
|
||||
"140693945143776"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
|
@ -289,7 +289,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Once defined we can **call** (i.e., \"execute\") a function with the **call operator** `()`. The formal parameters are filled in by passing variables or expressions as **arguments** to the function within the parentheses."
|
||||
"We can **call** (i.e., \"execute\") a function with the **call operator** `()` as often as we wish. The formal parameters are filled in by passing variables or expressions as **arguments** to the function within the parentheses."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -407,7 +407,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Notice how the parameters listed in a function's definition (i.e., `numbers`) and variables created inside it during execution (i.e., `evens` and `average`) are **local** to that function. That means they are only mapped to an object in memory while the function is being executed and de-referenced immediately when the function returns. We say they **go out of scope** once the function terminates."
|
||||
"Notice how the parameters listed in a function's definition (i.e., `numbers`) and variables created inside it during execution (i.e., `evens` and `average`) are **local** to that function. That means they only point to an object in memory *while* the function is being executed and de-referenced immediately when the function returns. We say they **go out of scope** once the function terminates."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -485,6 +485,17 @@
|
|||
"average"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "skip"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_evens%28numbers%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%0Arv%20%3D%20average_evens%28nums%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) visualizes what happens in memory: To be precise, in the exact moment when the function call is initiated and `nums` is passed in as the `numbers` argument, there are *two* pointers to the *same* `list` object (cf., steps 4-5 in the visualization). We also see how Python creates a *new* **frame** that holds the function's local scope (i.e., \"internal names\") in addition to the **global** frame. Frames are nothing but [namespaces](https://en.wikipedia.org/wiki/Namespace) to *isolate* the names of different **scopes** from each other. The list comprehension `[n for n in numbers if n % 2 == 0]` constitutes yet another frame that is in scope as the `list` object assigned to `evens` is *being* created (cf., steps 6-18). When the function returns, only the global frame is left (cf., steps 21-22)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
@ -504,7 +515,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"On the contrary, while a function is being executed, it can \"see\" the variables of the **enclosing scope** (i.e., \"outside\" of it). This is a common source of *semantic* errors. Consider the following stylized (and incorrect) example `average_wrong()`. The error is hard to spot with eyes: The function never references the `numbers` parameter but the `nums` variable in the **global scope** instead."
|
||||
"On the contrary, while a function is being executed, it can reference the variables of **enclosing scopes** (i.e., \"outside\" of it). This is a common source of *semantic* errors. Consider the following stylized (and incorrect) example `average_wrong()`. The error is hard to spot with eyes: The function never references the `numbers` parameter but the `nums` variable in the **global scope** instead."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -526,11 +537,22 @@
|
|||
" Returns:\n",
|
||||
" float: average\n",
|
||||
" \"\"\"\n",
|
||||
" evens = [n for n in nums if n % 2 == 0] # should reference numbers, not nums\n",
|
||||
" evens = [n for n in nums if n % 2 == 0] # should reference numbers not nums\n",
|
||||
" average = sum(evens) / len(evens)\n",
|
||||
" return average"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "skip"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"`nums` in the global scope is of course unchanged."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
|
@ -555,6 +577,17 @@
|
|||
"nums"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "skip"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"Sometimes a function might return a correct solution for *some* inputs ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
|
@ -576,7 +609,18 @@
|
|||
}
|
||||
],
|
||||
"source": [
|
||||
"average_wrong(nums) # the result is correct by accident!"
|
||||
"average_wrong(nums) # this is correct by accident"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"slideshow": {
|
||||
"slide_type": "skip"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"... but still be wrong *in general*."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -611,7 +655,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Also, observe how both `average_evens()` and `average_wrong()` use the same names for their respective parameters and variables internally. For sure, Python is smart enough to not mix them up. This is because each function call creates a temporary **[namespace](https://en.wikipedia.org/wiki/Namespace)** that *isolates* the local scope's names for usage only from within the function. As we saw in the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`)."
|
||||
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_wrong%28numbers%29%3A%0A%20%20%20%20evens%20%3D%20%5Bn%20for%20n%20in%20nums%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%0Arv%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 points to takes *12* computational steps, namely one for setting up an empty `list` object, *ten* for filling it with elements derived from `nums` in the global scope, and one to make `evens` point at it (cf., steps 6-18).\n",
|
||||
"\n",
|
||||
"The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside one function call but for potentially many calls occuring simultaneously as we will see in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb). It is the reason why we may re-use 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."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -633,9 +679,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Code gets even more confusing when variables by the same name from different scopes collide. In particular, what should we expect to happen if a function changes a globally defined variable internally?\n",
|
||||
"Code gets even more confusing when variables by the *same* name from *different* scopes collide. In particular, what should we expect to happen if a function \"changes\" a globally defined variable internally?\n",
|
||||
"\n",
|
||||
"`average_odds()` below works like `average_evens()` above except that it **[casts](https://en.wikipedia.org/wiki/Type_conversion)** (i.e., \"converts\") the elements of `numbers` as objects of type `int` with the [int()](https://docs.python.org/3/library/functions.html#int) built-in first before filtering and averaging them. In doing so, it introduces an *internal* variable `nums` whose name collides with the one in the global scope. The **inequality operator** `!=` is just the **reversed** version of `==`."
|
||||
"`average_odds()` below works like `average_evens()` above except that it **[casts](https://en.wikipedia.org/wiki/Type_conversion)** (i.e., \"converts\") the elements of `numbers` as objects of type `int` with the [int()](https://docs.python.org/3/library/functions.html#int) built-in first before filtering and averaging them. In doing so, it introduces an *internal* variable `nums` whose name collides with the one in the global scope. To filter for odd numbers, we use the **inequality operator** `!=` that is just the **reversed** version of `==`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -652,7 +698,7 @@
|
|||
" \"\"\"Calculate the average of all odd numbers in a list.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" numbers (list): a list of numbers; must be integers\n",
|
||||
" numbers (list): a list of numbers; must be integer-like\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" float: average\n",
|
||||
|
@ -671,7 +717,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"`nums` in the global scope is of course the same list from above."
|
||||
"`nums` in the global scope is still unchanged."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -706,7 +752,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"As good practice, let's first use inputs for which we can calculate the answer in our heads to verify that `average_odds()` is correct."
|
||||
"As good practice, let's first use inputs for which we can calculate the answer in our heads to \"verify\" that `average_odds()` is \"correct\"."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -730,7 +776,7 @@
|
|||
}
|
||||
],
|
||||
"source": [
|
||||
"average_odds([1, 100, 3, 100, 5]) # verify the function's correctness with predictable inputs"
|
||||
"average_odds([1.0, 10.0, 3.0, 10.0, 5.0]) # verify correctness with predictable inputs"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -776,7 +822,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Python, however, is again smart enough to keep the two `nums` variables apart. So the global `nums` is still pointing to the very same list object as before."
|
||||
"Python, however, is again smart enough to keep all the involved `nums` variables apart. So the global `nums` is still pointing to the very same `list` object as before."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -811,7 +857,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The reason why everything works just fine is that *every time* we (re-)assign an object to a variable inside a function with the `=` statement, this is done in the local scope by default. There are ways to change variables existing in an outer scope from within a function but we save that for a later chapter.\n",
|
||||
"The reason why everything just works is that *every time* we (re-)assign an object to a variable *inside* a function with the `=` statement, this is done in the *local* scope by default. There are ways to change variables existing in an outer scope from within a function but this is a rather advanced topic on its own.\n",
|
||||
"\n",
|
||||
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_odds%28numbers%29%3A%0A%20%20%20%20nums%20%3D%20%5Bint%28n%29%20for%20n%20in%20numbers%5D%0A%20%20%20%20odds%20%3D%20%5Bn%20for%20n%20in%20nums%20if%20n%20%25%202%20!%3D%200%5D%0A%20%20%20%20average%20%3D%20sum%28odds%29%20/%20len%28odds%29%0A%20%20%20%20return%20average%0A%0Arv%20%3D%20average_odds%28%5B1.0,%2010.0,%203.0,%2010.0,%205.0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how *two* `nums` variables exist in *different* scopes pointing to *different* objects (cf., steps 14-25) when we execute `average_odds([1.0, 10.0, 3.0, 10.0, 5.0])`.\n",
|
||||
"\n",
|
||||
"Variables whose names collide with the ones of variables in enclosing scopes - and the global scope is just the most enclosing scope - are said to **shadow** them.\n",
|
||||
"\n",
|
||||
|
@ -1122,7 +1170,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"So far we have only specified one parameter in each of our user-defined functions. In Chapter 1, however, we saw the built-in function [divmod()](https://docs.python.org/3/library/functions.html#divmod) taking two arguments. Obviously, the order of the numbers passed in mattered. Whenever we call a function and list its arguments in a comma seperated manner, we say that we pass in the arguments by position or refer to them as **positional arguments**."
|
||||
"So far we have only specified one parameter in each of our user-defined functions. In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb), however, we saw the built-in function [divmod()](https://docs.python.org/3/library/functions.html#divmod) taking two arguments. Obviously, the order of the numbers passed in mattered. Whenever we call a function and list its arguments in a comma seperated manner, we say that we pass in the arguments by position or refer to them as **positional arguments**."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2036,7 +2084,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"139655519584648"
|
||||
"140694050824664"
|
||||
]
|
||||
},
|
||||
"execution_count": 58,
|
||||
|
@ -2308,7 +2356,7 @@
|
|||
"source": [
|
||||
"Observe how the arguments passed to functions do not need to be just variables or simple literals. Instead, we can 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: An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is just ... well another operator. So both of the next two code cells are just expressions! They have no permanent side effect in memory. We can 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/master/01_elements.ipynb): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is just ... well another operator. So both of the next two code cells are just expressions! They have no permanent side effect in memory. We can 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)."
|
||||
]
|
||||
|
@ -2649,7 +2697,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"0.12717011866176486"
|
||||
"0.15268128055183228"
|
||||
]
|
||||
},
|
||||
"execution_count": 75,
|
||||
|
@ -2684,7 +2732,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<bound method Random.choice of <random.Random object at 0x562161984ba8>>"
|
||||
"<bound method Random.choice of <random.Random object at 0x56111ba1cba8>>"
|
||||
]
|
||||
},
|
||||
"execution_count": 76,
|
||||
|
@ -2733,7 +2781,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"8"
|
||||
"2"
|
||||
]
|
||||
},
|
||||
"execution_count": 78,
|
||||
|
@ -2881,7 +2929,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. We will look at it in depth in Chapter 9.\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, to execute terminal commands from within a Jupyter notebook, we just need to 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/master/00_start_up.ipynb), to execute terminal commands from within a Jupyter notebook, we just need to 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, will just confirm that."
|
||||
]
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Read Chapter 2 of the book. Then work through the ten review questions."
|
||||
"Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) of the book. Then work through the ten review questions."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"We analyzed every aspect of the `average_evens()` function in Chapter 2 except for the `if` part. While it seems to intuitively do what we expect it to, there is a whole lot more to be learned from taking it apart. In particular, the `if` can occur within both a **statement** as in our introductory example in Chapter 1 but also an **expression** as in `average_evens()`. This is analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both versions of the `if` is that it leads to code being executed for *parts* of the input only. It is our first way of **controlling** the **flow of execution** in a program.\n",
|
||||
"We analyzed every aspect of the `average_evens()` function in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) except for the `if` part. While it seems to intuitively do what we expect it to, there is a whole lot more to be learned from taking it apart. In particular, the `if` can occur within both a **statement** as in our introductory example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) but also an **expression** as in `average_evens()`. This is analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both versions of the `if` is that it leads to code being executed for *parts* of the input only. It is our first 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 and raising **exceptions**."
|
||||
]
|
||||
|
@ -139,7 +139,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"There are, however, cases where even well-behaved Python does not make us happy. Chapter 5 will provide more insights on that."
|
||||
"There are, however, cases where even well-behaved Python does not make us happy. Chapter 5 will provide more insights on this \"bug\"."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -189,7 +189,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"94709180875744"
|
||||
"94163040564192"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
|
@ -213,7 +213,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"94709180875712"
|
||||
"94163040564160"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
|
@ -281,9 +281,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Let's not confuse the boolean `False` with `None`, another special built-in object! We saw the latter before in Chapter 2 as the *implicit* return value of a function without a `return` statement.\n",
|
||||
"Let's not confuse the boolean `False` with `None`, another special built-in object! We saw the latter before in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) as the *implicit* return value of a function without a `return` statement.\n",
|
||||
"\n",
|
||||
"We might think of `None` in a boolean context indicating a \"maybe\" or even an \"unknown\" answer. But for Python, there are no \"maybe\" or \"unknown\" objects as we will see further below!\n",
|
||||
"We might think of `None` in a boolean context indicating a \"maybe\" or even an \"unknown\" answer; however, for Python, there are no \"maybe\" or \"unknown\" objects as we will see further below!\n",
|
||||
"\n",
|
||||
"Whereas `False` is of type `bool`, `None` is of type `NoneType`. So, they are totally unrelated. On the contrary, as both `True` and `False` are of the same type, we could call them \"siblings\"."
|
||||
]
|
||||
|
@ -313,7 +313,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"94709180862704"
|
||||
"94163040551152"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
|
@ -357,7 +357,7 @@
|
|||
}
|
||||
},
|
||||
"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 will never mutate its value in place (i.e., to re-use the bag analogy from Chapter 1, 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 already built in for *some* types.\n",
|
||||
"`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 will *not* mutate its value (i.e., to re-use the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb), 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 already built in for *some* types.\n",
|
||||
"\n",
|
||||
"We can verify this with either the `is` operator or by comparing memory addresses."
|
||||
]
|
||||
|
@ -512,7 +512,7 @@
|
|||
}
|
||||
],
|
||||
"source": [
|
||||
"42 != 123 # = \"not equal to\"; other programming languages sometimes use \"<>\" instead"
|
||||
"42 != 123 # = \"not equal to\"; other languages may use \"<>\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -672,7 +672,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Relational operators have a *higher precedence* over logical operators (cf., the [reference](https://docs.python.org/3/reference/expressions.html#operator-precedence)). So the following expression means what we intuitively think it does."
|
||||
"Relational operators have a **[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."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -825,7 +825,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"For even better readability, [some practitioner](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html) suggest to never use the `>` and `>=` operators (note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) and `&&` means `and` and `||` means `or`).\n",
|
||||
"For even better readability, [some practitioners](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html) suggest to *never* use the `>` and `>=` operators (note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) and `&&` means `and` and `||` means `or`).\n",
|
||||
"\n",
|
||||
"Python allows **chaining** relational operators that 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."
|
||||
]
|
||||
|
@ -899,7 +899,7 @@
|
|||
"source": [
|
||||
"The operands of the logical operators do not actually have to be *boolean* expressions as defined above but may be *any* kind of expression. If a sub-expression does *not* evaluate to an object of type `bool`, Python automatically casts the resulting object as such.\n",
|
||||
"\n",
|
||||
"For example, any non-zero numeric object effectively becomes `True`. While this behavior allows writing more concise and thus \"beautiful\" code, it is also a common source of confusion."
|
||||
"For example, any non-zero numeric object becomes `True`. While this behavior allows writing conciser and thus more \"beautiful\" code, it is also a common source of confusion."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1028,7 +1028,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"In a boolean context `None` is casted as `False`. So, `None` is really *not* a \"maybe\" answer but a \"no\"."
|
||||
"In a boolean context, `None` is casted as `False`! So, `None` is really *not* a \"maybe\" answer but a \"no\"."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1144,9 +1144,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"In order to write useful programs, we need to control the flow of execution, for example, to react to user input.\n",
|
||||
"In order 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 does that is referred to as **business logic**.\n",
|
||||
"\n",
|
||||
"One major language construct to do so is the **conditional statement** or `if` **statement** (cf., the [reference](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement)). It consists of:\n",
|
||||
"One major language construct to do so is the **[conditional statement](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement)** or `if` statement. It consists of:\n",
|
||||
"\n",
|
||||
"- *one* mandatory `if`-clause,\n",
|
||||
"- an *arbitrary* number of `elif`-clauses (i.e. \"else if\"), and\n",
|
||||
|
@ -1350,7 +1350,7 @@
|
|||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"z is positive\n"
|
||||
"z is odd\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -1602,7 +1602,7 @@
|
|||
"source": [
|
||||
"In the previous two chapters we already 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 occurence of such exceptions. All we need for that is a way to formulate a condition for that.\n",
|
||||
"\n",
|
||||
"For sure, this is such a common thing to do that Python provides its own language construct for it, namely the `try` statement (cf., the [reference](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement)).\n",
|
||||
"For sure, this is such a common thing to do that Python provides its own language construct for it, namely the `try` [statement](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement).\n",
|
||||
"\n",
|
||||
"In its simplest form, it comes with just two branches: `try` and `except`. The following basically tells Python to execute the code in the `try`-branch and if *anything* goes wrong, continue in the `except`-branch instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-branch is *not* executed."
|
||||
]
|
||||
|
@ -1711,7 +1711,7 @@
|
|||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Yes, division worked smoothly.\n",
|
||||
"Oops. Division by 0. How does that work?\n",
|
||||
"I am always printed\n"
|
||||
]
|
||||
}
|
||||
|
@ -1748,7 +1748,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"- **boolean expressions** evaluate either to `True` or `False`\n",
|
||||
"- **boolean expressions** evaluate to either `True` or `False`\n",
|
||||
"- **relational operators** compare operands according to \"human\" interpretations\n",
|
||||
"- **logical operators** combine boolean sub-expressions to more \"complex\" expressions\n",
|
||||
"- the **conditional statement** is a *major* concept to **control** the **flow of execution** depending on some **conditions**\n",
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Read Chapter 3 of the book. Then work through the seven review questions."
|
||||
"Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb) of the book. Then work through the seven review questions."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue