Streamline previous content

This commit is contained in:
Alexander Hess 2019-10-30 11:04:59 +01:00
commit 04d53956a3
11 changed files with 1097 additions and 410 deletions

View file

@ -139,7 +139,7 @@
}
},
"source": [
"There are, however, cases where even well-behaved Python does not make us happy. [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb) provides more insights into this \"bug.\""
"There are, however, cases where even well-behaved Python does not make us happy. [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb#Imprecision) provides more insights into this \"bug.\""
]
},
{
@ -189,7 +189,7 @@
{
"data": {
"text/plain": [
"94906834637792"
"94731133531104"
]
},
"execution_count": 5,
@ -213,7 +213,7 @@
{
"data": {
"text/plain": [
"94906834637760"
"94731133531072"
]
},
"execution_count": 6,
@ -281,7 +281,7 @@
}
},
"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/master/02_functions.ipynb) as the *implicit* return value of a function without a `return` statement.\n",
"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/master/02_functions.ipynb#Function-Definition) 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; however, for Python, there are no \"maybe\" or \"unknown\" objects, as we see further below!\n",
"\n",
@ -313,7 +313,7 @@
{
"data": {
"text/plain": [
"94906834624752"
"94731133518064"
]
},
"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 does *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 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 does *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#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."
]
@ -897,9 +897,11 @@
}
},
"source": [
"The operands of the logical operators do not need to be *boolean* expressions as defined above but may be *any* expression. If a sub-expression does *not* evaluate to an object of type `bool`, Python automatically casts it as such.\n",
"The operands of the logical operators do not need to be *boolean* expressions but may be *any* expression. If a sub-expression does *not* evaluate to an object of type `bool`, Python automatically casts it as such.\n",
"\n",
"For example, any non-zero numeric object becomes `True`. While this behavior allows writing more concise and thus more \"beautiful\" code, it is also a common source of confusion. `(x - 9)` is cast as `True` and then the overall expression evaluates to `True` as well."
"For example, any non-zero numeric object becomes `True`. While this behavior allows writing more concise and thus more \"beautiful\" code, it is also a common source of confusion.\n",
"\n",
"So, `(x - 9)` is cast as `True` and then the overall expression evaluates to `True` as well."
]
},
{
@ -1122,7 +1124,7 @@
}
},
"source": [
"Pythonistas often use the terms **truthy** or **falsy** to describe a non-boolean expression's behavior when used in place of a boolean one."
"Pythonistas use the terms **truthy** or **falsy** to describe a non-boolean expression's behavior when evaluated in a boolean context."
]
},
{
@ -1144,14 +1146,18 @@
}
},
"source": [
"When evaluating boolean expressions with logical operators in it, Python follows the **[short-circuiting](https://en.wikipedia.org/wiki/Short-circuit_evaluation)** strategy: First, the inner-most sub-expressions are evaluated. Second, with identical **[operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence)**, evaluation goes from left to right. Once it is clear what the overall truth value is, no more sub-expressions are evaluated, and the result is *immediately* returned.\n",
"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 sub-expressions are evaluated, and the result is *immediately* returned.\n",
"\n",
"In summary, data science practitioners must know *how* the following two generic expressions are evaluated:\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",
"- `x or y`: The `y` expression is evaluated *only if* `x` evaluates to `False`, in which case `y` is returned; otherwise, `x` is returned *without* even looking at `y`.\n",
"- `x and y`: The `y` expression is evaluated *only if* `x` evaluates to `True`. Then, if `y` also evaluates to `True`, it is returned; otherwise, `x` is returned.\n",
"The two rules can be summarized as:\n",
"\n",
"Let's look at a couple of examples."
"- `x or y`: If `x` is truthy, it is returned *without* evaluating `y`. Otherwise, `y` is evaluated *and* returned.\n",
"- `x and y`: If `x` is falsy, it is returned *without* evaluating `y`. Otherwise, `y` 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 sub-expressions are evaluated, we define a helper function `expr()` that prints out the only argument it is passed before returning it."
]
},
{
@ -1163,32 +1169,6 @@
}
},
"outputs": [],
"source": [
"x = 0\n",
"y = 1\n",
"z = 2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We define a helper function `expr()` that prints out the only argument it is passed before returning it. With `expr()`, we can see if a sub-expression is evaluated or not."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def expr(arg):\n",
" \"\"\"Print and return the only argument.\"\"\"\n",
@ -1204,12 +1184,12 @@
}
},
"source": [
"With the `or` operator, the first sub-expression that evaluates to `True` is returned."
"With the `or` operator, the first truthy sub-expression is returned."
]
},
{
"cell_type": "code",
"execution_count": 38,
"execution_count": 37,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1230,18 +1210,18 @@
"1"
]
},
"execution_count": 38,
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(x) or expr(y)"
"expr(0) or expr(1)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"execution_count": 38,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1261,18 +1241,18 @@
"1"
]
},
"execution_count": 39,
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(y) or expr(z)"
"expr(1) or expr(2) # 2 is not evaluated due to short-circuiting"
]
},
{
"cell_type": "code",
"execution_count": 40,
"execution_count": 39,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1293,13 +1273,13 @@
"1"
]
},
"execution_count": 40,
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(x) or expr(y) or expr(z)"
"expr(0) or expr(1) or expr(2) # 2 is not evaluated due to short-circuiting"
]
},
{
@ -1310,12 +1290,12 @@
}
},
"source": [
"If all sub-expressions evaluate to `False`, the last one is the result."
"If all sub-expressions are falsy, the last one is returned."
]
},
{
"cell_type": "code",
"execution_count": 41,
"execution_count": 40,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1337,13 +1317,13 @@
"0"
]
},
"execution_count": 41,
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(False) or expr([]) or expr(x)"
"expr(False) or expr([]) or expr(0)"
]
},
{
@ -1354,12 +1334,12 @@
}
},
"source": [
"With the `and` operator, the first sub-expression that evaluates to `False` is returned."
"With the `and` operator, the first falsy sub-expression is returned."
]
},
{
"cell_type": "code",
"execution_count": 42,
"execution_count": 41,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1373,6 +1353,38 @@
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(0) and expr(1) # 1 is not evaluated due to short-circuiting"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 1\n",
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
@ -1385,7 +1397,7 @@
}
],
"source": [
"expr(x) and expr(y)"
"expr(1) and expr(0)"
]
},
{
@ -1417,40 +1429,7 @@
}
],
"source": [
"expr(y) and expr(x)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 2\n",
"Arg: 1\n",
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(z) and expr(y) and expr(x)"
"expr(1) and expr(0) and expr(2) # 2 is not evaluated due to short-circuiting"
]
},
{
@ -1461,12 +1440,12 @@
}
},
"source": [
"If all sub-expressions evaluate to `True`, the last one is returned."
"If all sub-expressions are truthy, the last one is returned."
]
},
{
"cell_type": "code",
"execution_count": 45,
"execution_count": 44,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1487,13 +1466,13 @@
"2"
]
},
"execution_count": 45,
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(y) and expr(z)"
"expr(1) and expr(2)"
]
},
{
@ -1543,7 +1522,7 @@
},
{
"cell_type": "code",
"execution_count": 46,
"execution_count": 45,
"metadata": {
"code_folding": [],
"slideshow": {
@ -1557,7 +1536,7 @@
},
{
"cell_type": "code",
"execution_count": 47,
"execution_count": 46,
"metadata": {
"code_folding": [],
"slideshow": {
@ -1599,7 +1578,7 @@
},
{
"cell_type": "code",
"execution_count": 48,
"execution_count": 47,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1612,13 +1591,21 @@
},
{
"cell_type": "code",
"execution_count": 49,
"execution_count": 48,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"You read this just as often as you see heads when tossing a coin\n"
]
}
],
"source": [
"if random.random() > 0.5:\n",
" print(\"You read this just as often as you see heads when tossing a coin\")"
@ -1637,7 +1624,7 @@
},
{
"cell_type": "code",
"execution_count": 50,
"execution_count": 49,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1674,7 +1661,7 @@
},
{
"cell_type": "code",
"execution_count": 51,
"execution_count": 50,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1717,7 +1704,7 @@
},
{
"cell_type": "code",
"execution_count": 52,
"execution_count": 51,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1790,7 +1777,7 @@
},
{
"cell_type": "code",
"execution_count": 53,
"execution_count": 52,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1814,7 +1801,7 @@
},
{
"cell_type": "code",
"execution_count": 54,
"execution_count": 53,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1830,7 +1817,7 @@
},
{
"cell_type": "code",
"execution_count": 55,
"execution_count": 54,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1843,7 +1830,7 @@
"9"
]
},
"execution_count": 55,
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
@ -1865,7 +1852,7 @@
},
{
"cell_type": "code",
"execution_count": 56,
"execution_count": 55,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1878,7 +1865,7 @@
},
{
"cell_type": "code",
"execution_count": 57,
"execution_count": 56,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1891,7 +1878,7 @@
"9"
]
},
"execution_count": 57,
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
@ -1913,7 +1900,7 @@
},
{
"cell_type": "code",
"execution_count": 58,
"execution_count": 57,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1926,7 +1913,7 @@
},
{
"cell_type": "code",
"execution_count": 59,
"execution_count": 58,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1939,7 +1926,7 @@
"9"
]
},
"execution_count": 59,
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
@ -1956,7 +1943,7 @@
}
},
"source": [
"Conditional expressions may not only be used in the way described in this section. We already saw them as part of a *list comprehension* in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) and [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) and revisit this in Chapter 7 in greater detail."
"Conditional expressions may not only be used in the way described in this section. We already saw them as part of a *list comprehension* in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) and [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) and revisit this construct in greater detail in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#List-Comprehensions)."
]
},
{
@ -1987,7 +1974,7 @@
},
{
"cell_type": "code",
"execution_count": 60,
"execution_count": 59,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -2000,7 +1987,7 @@
},
{
"cell_type": "code",
"execution_count": 61,
"execution_count": 60,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -2039,7 +2026,7 @@
},
{
"cell_type": "code",
"execution_count": 62,
"execution_count": 61,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -2078,7 +2065,7 @@
},
{
"cell_type": "code",
"execution_count": 63,
"execution_count": 62,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -2089,7 +2076,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"
]
}