Streamline previous content

This commit is contained in:
Alexander Hess 2019-11-20 11:00:24 +01:00
commit ca8fefdce1
13 changed files with 5091 additions and 3409 deletions

View file

@ -21,9 +21,9 @@
"source": [
"After learning about the basic building blocks of expressing and structuring the business logic in programs, we focus our attention on the **data types** Python offers us, both built-in and available via the [standard library](https://docs.python.org/3/library/index.html) or third-party packages.\n",
"\n",
"We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. 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), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n",
"We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. To reuse 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), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n",
"\n",
"[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb) and Chapter 8 then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 9 completes the picture by introducing language constructs to create custom types.\n",
"[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb) and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 9 completes the picture by introducing language constructs to create custom types.\n",
"\n",
"We have already seen many hints indicating that numbers are not as trivial to work with as it seems at first sight:\n",
"\n",
@ -92,7 +92,7 @@
{
"data": {
"text/plain": [
"140087541220560"
"140673805309168"
]
},
"execution_count": 2,
@ -307,7 +307,7 @@
}
},
"source": [
"We may pass a `str` object formatted this way as the argument to the [int()](https://docs.python.org/3/library/functions.html#int) built-in, together with `base=2`, to (re-)create an `int` object, for example, with the value of `3`."
"We may pass a `str` object formatted this way as the argument to the [int()](https://docs.python.org/3/library/functions.html#int) built-in, together with `base=2`, to create an `int` object, for example, with the value of `3`."
]
},
{
@ -883,7 +883,7 @@
}
},
"source": [
"To (re-)create an `int` object with the value `177`, we call the [int()](https://docs.python.org/3/library/functions.html#int) built-in with a properly formatted `str` object and `base=16` as arguments."
"To obtain a *new* `int` object with the value `177`, we call the [int()](https://docs.python.org/3/library/functions.html#int) built-in with a properly formatted `str` object and `base=16` as arguments."
]
},
{
@ -2115,7 +2115,7 @@
{
"data": {
"text/plain": [
"140087541402072"
"140673805486768"
]
},
"execution_count": 63,
@ -5498,7 +5498,7 @@
{
"data": {
"text/plain": [
"140087540555856"
"140673804641712"
]
},
"execution_count": 176,
@ -6054,7 +6054,7 @@
}
},
"source": [
"Also, a conjugate() method is bound to every `complex` object. The [complex conjugate](https://en.wikipedia.org/wiki/Complex_conjugate) is defined to be the complex number with identical real part but an imaginary part reversed in sign."
"Also, a `conjugate()` method is bound to every `complex` object. The [complex conjugate](https://en.wikipedia.org/wiki/Complex_conjugate) is defined to be the complex number with identical real part but an imaginary part reversed in sign."
]
},
{
@ -6111,17 +6111,17 @@
}
},
"source": [
"Analogous to the discussion of containers and iterables in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables), we contrast the *concrete* numeric data types in this chapter with the *abstract* ideas behind [numbers in mathematics](https://en.wikipedia.org/wiki/Number).\n",
"Analogous to the discussion of *containers* and *iterables* in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables), we contrast the *concrete* numeric data types in this chapter with the *abstract* ideas behind [numbers in mathematics](https://en.wikipedia.org/wiki/Number).\n",
"\n",
"The figure below summarizes five *major* sets of [numbers in mathematics](https://en.wikipedia.org/wiki/Number) as we know them from high school:\n",
"\n",
"- $\\mathbb{N}$: [Natural numbers](https://en.wikipedia.org/wiki/Natural_number) are all non-negative count numbers, e.g., $0, 1, 2, ...$\n",
"- $\\mathbb{Z}$: [Integers](https://en.wikipedia.org/wiki/Integer) are all numbers *without* a fractional component, e.g., $-1, 0, 1, ...$\n",
"- $\\mathbb{Q}$: [Rational numbers](https://en.wikipedia.org/wiki/Rational_number) are all numbers that can be expressed as a quotient of two integers, e.g., $-\\frac{1}{2}, 0, \\frac{1}{2}, ...$\n",
"- $\\mathbb{R}$: [Real numbers](https://en.wikipedia.org/wiki/Real_number) are all numbers that can be represented as a distance along a line (negative means \"reversed\"), e.g., $\\sqrt{2}, \\pi, \\text{e}, ...$\n",
"- $\\mathbb{R}$: [Real numbers](https://en.wikipedia.org/wiki/Real_number) are all numbers that can be represented as a distance along a line, and negative means \"reversed,\" e.g., $\\sqrt{2}, \\pi, \\text{e}, ...$\n",
"- $\\mathbb{C}$: [Complex numbers](https://en.wikipedia.org/wiki/Complex_number) are all numbers of the form $a + b\\textbf{i}$ where $a$ and $b$ are real numbers and $\\textbf{i}$ is the [imaginary number](https://en.wikipedia.org/wiki/Imaginary_number), e.g., $0, \\textbf{i}, 1 + \\textbf{i}, ...$\n",
"\n",
"In the listed order, the five sets are perfect subsets and $\\mathbb{C}$ is the largest set (to be precise, all sets are infinite, but they still have a different number of elements)."
"In the listed order, the five sets are perfect subsets of the respective following sets, and $\\mathbb{C}$ is the largest set (cf., the figure below illustrates that observation as well). To be precise, all sets are infinite, but they still have a different number of elements."
]
},
{
@ -6143,13 +6143,13 @@
}
},
"source": [
"The *concrete* data types introduced in this chapter are all *imperfect* models of *abstract* mathematical ideas.\n",
"The data types introduced in this chapter are all *imperfect* models of *abstract* mathematical ideas.\n",
"\n",
"The `int` and `Fraction` types are the models \"closest\" to the idea they implement: Whereas $\\mathbb{Z}$ and $\\mathbb{Q}$ are, by definition, infinite, every computer runs out of bits when representing sufficiently large integers or fractions with a sufficiently large number of decimals. However, within a system-dependent minimum and maximum integer range, we can model an integer or fraction without any loss in precision.\n",
"The `int` and `Fraction` types are the models \"closest\" to the idea they implement: Whereas $\\mathbb{Z}$ and $\\mathbb{Q}$ are, by definition, infinite, every computer runs out of bits when representing sufficiently large integers or fractions with a sufficiently large number of decimals. However, within a system-dependent range, we can model an integer or fraction without any loss in precision.\n",
"\n",
"For the other types, in particular, the `float` type, the implications of their imprecision are discussed in detail above.\n",
"\n",
"The abstract concepts behind the four outer-most mathematical sets are part of Python since [PEP 3141](https://www.python.org/dev/peps/pep-3141/) in 2007. The [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines what programmers call the **[numerical tower](https://en.wikipedia.org/wiki/Numerical_tower)**, a collection of five **[abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type)**, or **abstract base classes** as they are called in Python jargon:\n",
"The abstract concepts behind the four outer-most mathematical sets are formalized in Python since [PEP 3141](https://www.python.org/dev/peps/pep-3141/) in 2007. The [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines what programmers call the **[numerical tower](https://en.wikipedia.org/wiki/Numerical_tower)**, a collection of five **[abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type)**, or **abstract base classes** (ABCs) as they are called in Python jargon:\n",
"\n",
"- `numbers.Number`: \"any number\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Number))\n",
"- `numbers.Complex`: \"all complex numbers\" (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex))\n",
@ -6220,9 +6220,9 @@
"source": [
"As a reminder, the built-in [help()](https://docs.python.org/3/library/functions.html#help) function is always our friend.\n",
"\n",
"The abstract types' docstrings are unsurprisingly similar to the corresponding concrete types' docstrings (for now, let's not worry about the dunder-style names in the docstrings).\n",
"The ABCs' docstrings are unsurprisingly similar to the corresponding data types' docstrings. For now, let's not worry about the dunder-style names in the docstrings.\n",
"\n",
"For example, both `numbers.Complex` and `complex` list the `imag` and `real` attributes."
"For example, both `numbers.Complex` and `complex` list the `imag` and `real` attributes shown above."
]
},
{
@ -6231,7 +6231,7 @@
"metadata": {
"scrolled": true,
"slideshow": {
"slide_type": "slide"
"slide_type": "skip"
}
},
"outputs": [
@ -6336,17 +6336,6 @@
"help(numbers.Complex)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"For sure, Python understands the built-in types as literals."
]
},
{
"cell_type": "code",
"execution_count": 201,
@ -6509,9 +6498,9 @@
}
},
"source": [
"One way to use *abstract* data types is to use them in place of a *concrete* data type.\n",
"The primary purpose of ABCs is to classify the *concrete* data types and standardize how they behave.\n",
"\n",
"For example, we may pass them as arguments to the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function and check in which of the five mathematical sets the object `1 / 10` is."
"For, example, as all numeric data types are `Complex` numbers in the abstract sense, they all work with the built-in [abs()](https://docs.python.org/3/library/functions.html#abs) function (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Complex)). While it is intuitively clear what the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) (i.e., \"distance\" to $0$) of an integer, a fraction, or any real number is, [abs()](https://docs.python.org/3/library/functions.html#abs) calculates the equivalent of that for complex numbers. That concept is called the [magnitude](https://en.wikipedia.org/wiki/Magnitude_%28mathematics%29) of a number, and is really a *generalization* of the absolute value."
]
},
{
@ -6526,7 +6515,7 @@
{
"data": {
"text/plain": [
"True"
"42"
]
},
"execution_count": 202,
@ -6535,7 +6524,7 @@
}
],
"source": [
"isinstance(1 / 10, float)"
"abs(-42)"
]
},
{
@ -6543,14 +6532,14 @@
"execution_count": 203,
"metadata": {
"slideshow": {
"slide_type": "fragment"
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
"Decimal('0.1')"
]
},
"execution_count": 203,
@ -6559,7 +6548,7 @@
}
],
"source": [
"isinstance(1 / 10, numbers.Number)"
"abs(Decimal(\"-0.1\"))"
]
},
{
@ -6574,7 +6563,7 @@
{
"data": {
"text/plain": [
"True"
"5.0"
]
},
"execution_count": 204,
@ -6583,12 +6572,263 @@
}
],
"source": [
"isinstance(1 / 10, numbers.Complex)"
"abs(4 - 3j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"On the contrary, only `Real` numbers in the abstract sense may be rounded with the built-in [round()](https://docs.python.org/3/library/functions.html#round) function."
]
},
{
"cell_type": "code",
"execution_count": 205,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"42"
]
},
"execution_count": 205,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"round(42.1)"
]
},
{
"cell_type": "code",
"execution_count": 206,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 206,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"round(Decimal(\"0.1\"))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"`Complex` numbers are two-dimensional. So, rounding makes no sense and raises a `TypeError`."
]
},
{
"cell_type": "code",
"execution_count": 207,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "type complex doesn't define __round__ method",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-207-44b2943ede89>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mround\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m4\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m3j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: type complex doesn't define __round__ method"
]
}
],
"source": [
"round(4 + 3j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Knowing what ABCs a numeric type adheres to, is not only important in the context of built-ins. The [trunc()](https://docs.python.org/3/library/math.html#math.trunc) function from the [math](https://docs.python.org/3/library/math.html) module in the [standard library](https://docs.python.org/3/library/index.html), for example, only works with `Real` types (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Real))."
]
},
{
"cell_type": "code",
"execution_count": 208,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"import math"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"[trunc()](https://docs.python.org/3/library/math.html#math.trunc) cuts off a number's decimals."
]
},
{
"cell_type": "code",
"execution_count": 209,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 209,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"math.trunc(9 / 10)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"A `Complex` number leads to a `TypeError`."
]
},
{
"cell_type": "code",
"execution_count": 210,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"ename": "TypeError",
"evalue": "type complex doesn't define __trunc__ method",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-210-7121e57d9639>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0.9\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: type complex doesn't define __trunc__ method"
]
}
],
"source": [
"math.trunc(0.9 + 1j)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"Another way to use ABCs is in place of a *concrete* data type.\n",
"\n",
"For example, we may pass them as arguments to the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function and check in which of the five mathematical sets the object `1 / 10` is."
]
},
{
"cell_type": "code",
"execution_count": 211,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 211,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, float) # we know that from before"
]
},
{
"cell_type": "code",
"execution_count": 212,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 212,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Number) # a float object is a Number in the abstract sense"
]
},
{
"cell_type": "code",
"execution_count": 213,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -6601,13 +6841,37 @@
"True"
]
},
"execution_count": 205,
"execution_count": 213,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Real)"
"isinstance(1 / 10, numbers.Complex) # float objects are always also Complex numbers"
]
},
{
"cell_type": "code",
"execution_count": 214,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 214,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Real) # a float object's purpose is to model a Real number"
]
},
{
@ -6623,7 +6887,7 @@
},
{
"cell_type": "code",
"execution_count": 206,
"execution_count": 215,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -6636,13 +6900,13 @@
"False"
]
},
"execution_count": 206,
"execution_count": 215,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isinstance(1 / 10, numbers.Rational)"
"isinstance(1 / 10, numbers.Rational) # the type of `1 / 10` is what is important, not its value"
]
},
{
@ -6658,7 +6922,7 @@
},
{
"cell_type": "code",
"execution_count": 207,
"execution_count": 216,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -6671,7 +6935,7 @@
"True"
]
},
"execution_count": 207,
"execution_count": 216,
"metadata": {},
"output_type": "execute_result"
}
@ -6682,7 +6946,7 @@
},
{
"cell_type": "code",
"execution_count": 208,
"execution_count": 217,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -6695,7 +6959,7 @@
"False"
]
},
"execution_count": 208,
"execution_count": 217,
"metadata": {},
"output_type": "execute_result"
}
@ -6723,46 +6987,9 @@
}
},
"source": [
"Replacing *concrete* data types with *abstract* ones is particularly valuable in the context of input validation: The revised version of the `factorial()` function below allows its user to take advantage of *duck typing*: If a real but non-integer argument `n` is passed in, `factorial()` tries to cast `n` as an `int` object with the [trunc()](https://docs.python.org/3/library/math.html#math.trunc) function from the [math](https://docs.python.org/3/library/math.html) module in the [standard library](https://docs.python.org/3/library/index.html). [trunc()](https://docs.python.org/3/library/math.html#math.trunc) cuts off all decimals and any *concrete* numeric type implementing the *abstract* `numbers.Real` type supports it (cf., [documentation](https://docs.python.org/3/library/numbers.html#numbers.Real)).\n",
"Replacing *concrete* data types with ABCs is particularly valuable in the context of input validation: The revised version of the `factorial()` function below allows its user to take advantage of *duck typing*: If a real but non-integer argument `n` is passed in, `factorial()` tries to cast `n` as an `int` object with [math.trunc()](https://docs.python.org/3/library/math.html#math.trunc).\n",
"\n",
"Two popular and distinguished Pythonistas, [Luciano Ramalho](https://github.com/ramalho) and [Alex Martelli](https://en.wikipedia.org/wiki/Alex_Martelli), coin the term **goose typing** to specifically mean using the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function with an *abstract base class* (cf., Chapter 11 in this [book](https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008) or this [summary](https://dgkim5360.github.io/blog/python/2017/07/duck-typing-vs-goose-typing-pythonic-interfaces/) thereof)."
]
},
{
"cell_type": "code",
"execution_count": 209,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"import math"
]
},
{
"cell_type": "code",
"execution_count": 210,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 210,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"math.trunc(1 / 10)"
"Two popular and distinguished Pythonistas, [Luciano Ramalho](https://github.com/ramalho) and [Alex Martelli](https://en.wikipedia.org/wiki/Alex_Martelli), coin the term **goose typing** to specifically mean using the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function with an ABC (cf., Chapter 11 in this [book](https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008) or this [summary](https://dgkim5360.github.io/blog/python/2017/07/duck-typing-vs-goose-typing-pythonic-interfaces/) thereof)."
]
},
{
@ -6778,7 +7005,7 @@
},
{
"cell_type": "code",
"execution_count": 211,
"execution_count": 218,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -6810,7 +7037,7 @@
"\n",
" if n < 0:\n",
" raise ValueError(\"Factorial is not defined for negative integers\")\n",
" elif n == 0:\n",
" elif n == 0: # = base case\n",
" return 1\n",
" return n * factorial(n - 1)"
]
@ -6828,7 +7055,7 @@
},
{
"cell_type": "code",
"execution_count": 212,
"execution_count": 219,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -6841,7 +7068,7 @@
"1"
]
},
"execution_count": 212,
"execution_count": 219,
"metadata": {},
"output_type": "execute_result"
}
@ -6852,7 +7079,7 @@
},
{
"cell_type": "code",
"execution_count": 213,
"execution_count": 220,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -6865,7 +7092,7 @@
"6"
]
},
"execution_count": 213,
"execution_count": 220,
"metadata": {},
"output_type": "execute_result"
}
@ -6876,7 +7103,7 @@
},
{
"cell_type": "code",
"execution_count": 214,
"execution_count": 221,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -6889,7 +7116,7 @@
"6"
]
},
"execution_count": 214,
"execution_count": 221,
"metadata": {},
"output_type": "execute_result"
}
@ -6906,12 +7133,12 @@
}
},
"source": [
"With the keyword-only argument `strict`, we can control whether or not a passed in `float` object may be rounded. By default, this is not allowed and results in a `TypeError`."
"With the keyword-only argument `strict`, we can control whether or not a passed in `float` object may come with decimals that are then truncated. By default, this is not allowed and results in a `TypeError`."
]
},
{
"cell_type": "code",
"execution_count": 215,
"execution_count": 222,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -6925,8 +7152,8 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-215-188b816be8b6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-211-60ca579e64ac>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\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 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not an integer-like value; it has decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-222-188b816be8b6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3.1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-218-d2a63febf49e>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mReal\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 17\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mstrict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"n is not an integer-like value; it has decimals\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: n is not an integer-like value; it has decimals"
]
}
@ -6935,9 +7162,20 @@
"factorial(3.1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"In non-strict mode, the passed in `3.1` is truncated into `3` resulting in a factorial of `6`."
]
},
{
"cell_type": "code",
"execution_count": 216,
"execution_count": 223,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -6950,7 +7188,7 @@
"6"
]
},
"execution_count": 216,
"execution_count": 223,
"metadata": {},
"output_type": "execute_result"
}
@ -6967,12 +7205,12 @@
}
},
"source": [
"For `complex` numbers, `factorial()` still raises a `TypeError`."
"For `complex` numbers, `factorial()` still raises a `TypeError` because they are neither an `Integral` nor a `Real` number."
]
},
{
"cell_type": "code",
"execution_count": 217,
"execution_count": 224,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -6986,8 +7224,8 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-217-7296a74f5dcf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-211-60ca579e64ac>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 21\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 22\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-224-7296a74f5dcf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2j\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-218-d2a63febf49e>\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n, strict)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 21\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is only defined for integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 22\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: Factorial is only defined for integers"
]
}
@ -7016,20 +7254,20 @@
},
"source": [
"There exist three numeric types in core Python:\n",
"- `int`: a near-perfect model for whole numbers (i.e., the set $\\mathbb{Z}$); inherently precise\n",
"- `float`: the \"gold\" standard to approximate real numbers (i.e., the set $\\mathbb{R}$); inherently imprecise\n",
"- `complex`: layer on top of the `float` type; therefore inherently imprecise\n",
"- `int`: a near-perfect model for whole numbers (i.e., $\\mathbb{Z}$); inherently precise\n",
"- `float`: the \"gold\" standard to approximate real numbers (i.e., $\\mathbb{R}$); inherently imprecise\n",
"- `complex`: layer on top of the `float` type to approximate complex numbers (i.e., $\\mathbb{C}$); inherently imprecise\n",
"\n",
"Furthermore, the [standard library](https://docs.python.org/3/library/index.html) adds two more types that can be used as substitutes for `float` objects:\n",
"Furthermore, the [standard library](https://docs.python.org/3/library/index.html) provides two more types that can be used as substitutes for the `float` type:\n",
"- `Decimal`: similar to `float` but allows customizing the precision; still inherently imprecise\n",
"- `Fraction`: a near-perfect model for rational numbers (i.e., the set $\\mathbb{Q}$); built on top of the `int` type and therefore inherently precise\n",
"- `Fraction`: a near-perfect model for rational numbers (i.e., $\\mathbb{Q}$); built on top of the `int` type and therefore inherently precise\n",
"\n",
"The *important* takeaways for the data science practitioner are:\n",
"\n",
"1. **Do not mix** precise and imprecise data types, and\n",
"2. actively expect `nan` results when working with `float` numbers as there are no **loud failures**.\n",
"\n",
"The **numerical tower** is Python's way of implementing the various **abstract** ideas of what numbers are in mathematics."
"The **numerical tower** is Python's way of implementing various **abstract** ideas of what numbers are in mathematics."
]
}
],