From ca8fefdce19c731cc25e6fe498394a7991076a81 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Wed, 20 Nov 2019 11:00:24 +0100 Subject: [PATCH] Streamline previous content --- 00_start_up.ipynb | 8 +- 01_elements.ipynb | 97 +- 01_elements_review_and_exercises.ipynb | 4 +- 02_functions.ipynb | 58 +- 02_functions_review_and_exercises.ipynb | 58 +- 03_conditionals.ipynb | 12 +- 03_conditionals_review_and_exercises.ipynb | 30 +- 04_iteration.ipynb | 160 +- 04_iteration_review_and_exercises.ipynb | 23 +- 05_numbers.ipynb | 456 ++- 05_numbers_review_and_exercises.ipynb | 22 +- 06_text.ipynb | 660 ++-- 07_sequences.ipynb | 3920 ++++++++++++++------ 13 files changed, 3595 insertions(+), 1913 deletions(-) diff --git a/00_start_up.ipynb b/00_start_up.ipynb index 97fe84b..9aed12d 100644 --- a/00_start_up.ipynb +++ b/00_start_up.ipynb @@ -585,7 +585,7 @@ " - replaced the infamous course on the [Scheme](https://groups.csail.mit.edu/mac/projects/scheme/) language (cf., [source](https://news.ycombinator.com/item?id=602307))\n", "- **[Google](https://www.google.com/)**\n", " - used the strategy **\"Python where we can, C++ where we must\"** from its early days on to stay flexible in a rapidly changing environment (cf., [source](https://stackoverflow.com/questions/2560310/heavy-usage-of-python-at-google))\n", - " - the very first web-crawler was written in **Java and so difficult to maintain** that it was **re-written in Python** right away (cf., [source](https://www.amazon.com/Plex-Google-Thinks-Works-Shapes/dp/1416596585/ref=sr_1_1?ie=UTF8&qid=1539101827&sr=8-1&keywords=in+the+plex))\n", + " - the very first web-crawler was written in **Java and so difficult to maintain** that it was **rewritten in Python** right away (cf., [source](https://www.amazon.com/Plex-Google-Thinks-Works-Shapes/dp/1416596585/ref=sr_1_1?ie=UTF8&qid=1539101827&sr=8-1&keywords=in+the+plex))\n", " - Python and C++, Java, and Go are the only four server-side languages to be deployed to production\n", " - Guido van Rossom was hired by Google from 2005 to 2012 to advance the language there\n", "- **[NASA](https://www.nasa.gov/)** open-sources many of its projects, often written in Python and regarding analyses with big data (cf., [source](https://code.nasa.gov/language/python/))\n", @@ -605,7 +605,7 @@ } }, "source": [ - "As images tell more than words, here are two plots of popular languages' \"market shares\" based on the number of questions asked on [Stack Overflow](https://stackoverflow.blog/2017/09/06/incredible-growth-python/), the most relevant platform for answering programming related questions: As of late 2017, Python surpassed [Java](https://www.java.com/en/), heavily used in big corporates, and [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript), the \"language of the internet\" that does everything in web browsers, in popularity. Two blog posts from \"technical\" people explain this in more depth to the layman: [Stack Overflow](https://stackoverflow.blog/2017/09/14/python-growing-quickly/) and [DataCamp](https://www.datacamp.com/community/blog/python-scientific-computing-case)." + "As images tell more than words, here are two plots of popular languages' \"market shares\" based on the number of questions asked on [Stack Overflow](https://stackoverflow.blog/2017/09/06/incredible-growth-python/), the most relevant platform for answering programming-related questions: As of late 2017, Python surpassed [Java](https://www.java.com/en/), heavily used in big corporates, and [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript), the \"language of the internet\" that does everything in web browsers, in popularity. Two blog posts from \"technical\" people explain this in more depth to the layman: [Stack Overflow](https://stackoverflow.blog/2017/09/14/python-growing-quickly/) and [DataCamp](https://www.datacamp.com/community/blog/python-scientific-computing-case)." ] }, { @@ -715,7 +715,7 @@ "- **Managers**: People that need to organize things and command others (like a \"boss\"). Their schedule is usually organized by the hour or even 30-minute intervals.\n", "- **Makers**: People that create things (like programmers, artists, or writers). Such people think in half days or full days.\n", "\n", - "Have you ever wondered why so many tech people work during nights and sleep at \"weird\" times? The reason is that many programming related tasks require a \"flow\" state in one's mind that is hard to achieve when one can get interrupted, even if it is only for one short question. Graham describes that only knowing that one has an appointment in three hours can cause a programmer to not get into a flow state.\n", + "Have you ever wondered why so many tech people work during nights and sleep at \"weird\" times? The reason is that many programming-related tasks require a \"flow\" state in one's mind that is hard to achieve when one can get interrupted, even if it is only for one short question. Graham describes that only knowing that one has an appointment in three hours can cause a programmer to not get into a flow state.\n", "\n", "As a result, do not set aside a certain amount of time for learning something but rather plan in an **entire evening** or a **rainy Sunday** where you can work on a problem in an **open end** setting. And do not be surprised anymore to hear \"I looked at it over the weekend\" from a programmer." ] @@ -795,7 +795,7 @@ " 5. [Bits & Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb)\n", " 6. [Bytes & Text](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb)\n", " 7. [Sequential Data](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb)\n", - " 8. Mappings & Sets\n", + " 8. [Mappings & Sets](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings.ipynb)\n", "- How can we create custom data types?\n", " 9. Object-Orientation" ] diff --git a/01_elements.ipynb b/01_elements.ipynb index fed6458..07d6774 100644 --- a/01_elements.ipynb +++ b/01_elements.ipynb @@ -48,7 +48,7 @@ "source": [ "As our introductory example, we want to calculate the *average* of all *evens* in a **list** of numbers: `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]`.\n", "\n", - "While we could try to develop 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\"), we solve the task programmatically instead.\n", + "While we are used to finding an [analytical solution](https://math.stackexchange.com/questions/935405/what-s-the-difference-between-analytical-and-numerical-approaches-to-problems/935446#935446) in math (i.e., derive some equation with \"pen and paper\"), we solve this task *programmatically* instead.\n", "\n", "We start by creating a list called `numbers` that holds all the individual numbers between **brackets** `[` and `]`." ] @@ -114,7 +114,7 @@ "\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", + "The `if number % 2 == 0` may look confusing at first sight. Both `%` and `==` must have an unintuitive meaning here. Luckily, the **comment** in the same line after the `#` symbol has the answer: The program does something only for an even `number`.\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` are 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", @@ -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 **expression**. This output can be suppressed by ending the last line with a semicolon `;`." + "By default, Jupyter notebooks show the value of the **expression** in the last line of a code cell only. 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 use the built-in [print()](https://docs.python.org/3/library/functions.html#print) **function**. Here, the parentheses `()` indicate that we execute code defined somewhere else." + "To visualize something before the end of the cell, we use the built-in [print()](https://docs.python.org/3/library/functions.html#print) **function**. Here, the parentheses `()` indicate that we execute code written somewhere else." ] }, { @@ -331,9 +331,9 @@ "\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).\n", "\n", - "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 continue this thought further below when we compare **expressions** with **statements**.\n", + "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 develop this thought further at the end of this chapter 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." + "Let's see some examples of operators. We start with the binary `+` and the `-` operators for addition and subtraction. Binary operators mimic what mathematicians call [infix notation](https://en.wikipedia.org/wiki/Infix_notation) and have the expected meaning." ] }, { @@ -392,7 +392,7 @@ } }, "source": [ - "The `-` operator is used as a unary operator as well. Then it just flips the sign of a number." + "The `-` operator may be used as a unary operator as well. Then it just flips the sign of a number." ] }, { @@ -617,7 +617,9 @@ "source": [ "The remainder is `0` *only if* a number is *divisible* by another.\n", "\n", - "A popular convention in both, computer science and mathematics, is to abbreviate \"only if\" as **iff**, which is short for \"**[if and only if](https://en.wikipedia.org/wiki/If_and_only_if)**.\" The iff means that a remainder of `0` implies that a number is divisible by another but also that a number divisible by another implies a remainder of `0`. The implication goes in *both* directions!" + "A popular convention in both, computer science and mathematics, is to abbreviate \"only if\" as **iff**, which is short for \"**[if and only if](https://en.wikipedia.org/wiki/If_and_only_if)**.\" The iff means that a remainder of `0` implies that a number is divisible by another but also that a number divisible by another implies a remainder of `0`. The implication goes in *both* directions!\n", + "\n", + "So, `49` is divisible by `7`." ] }, { @@ -652,7 +654,7 @@ } }, "source": [ - "Modulo division is also useful if we, for example, need to get the last couple of digits of a large integer." + "Modulo division is also useful if we want to extract the last couple of digits in a large integer." ] }, { @@ -711,7 +713,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 but a function. Also, [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers and not just one object." + "The built-in [divmod()](https://docs.python.org/3/library/functions.html#divmod) function combines the integer and modulo divisions into one operation. However, this is not an operator but a function. Also, [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers and not just one." ] }, { @@ -781,7 +783,7 @@ } }, "source": [ - "The standard [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., \"PEMDAS\" rule)." + "The standard [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., [PEMDAS](http://mathworld.wolfram.com/PEMDAS.html) rule) when several operators are combined." ] }, { @@ -988,7 +990,7 @@ { "data": { "text/plain": [ - "140706351197104" + "140398796190992" ] }, "execution_count": 28, @@ -1012,7 +1014,7 @@ { "data": { "text/plain": [ - "140706351380256" + "140398796375888" ] }, "execution_count": 29, @@ -1036,7 +1038,7 @@ { "data": { "text/plain": [ - "140706351003760" + "140398796056176" ] }, "execution_count": 30, @@ -1056,7 +1058,7 @@ } }, "source": [ - "These addresses are *not* meaningful for anything other than checking if two variables **point** at the same object. Let's create a second variable `d` and also set it to `789`." + "These addresses are *not* meaningful for anything other than checking if two variables reference the *same* object. Let's create a second variable `d` and also set it to `789`." ] }, { @@ -1507,7 +1509,7 @@ } }, "source": [ - "In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its literal output for `str` objects. Both types of quotes may be used interchangeably." + "In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its *literal* notation for `str` objects. Both types of quotes may be used interchangeably." ] }, { @@ -1825,7 +1827,7 @@ "source": [ "Thus, adhering to just syntax rules is *never* enough. Over time, **best practices** and **style guides** were created to make it less likely for a developer to mess up a program and also to allow \"onboarding\" him as a contributor to an established code base, often called **legacy code**, faster. These rules are not enforced by Python itself: Badly styled code still runs. At the very least, Python programs should be styled according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) and documented \"inline\" (i.e., in the code itself) according to [PEP 257](https://www.python.org/dev/peps/pep-0257/).\n", "\n", - "An easier to read version of PEP 8 is [here](https://pep8.org/). The video below features a well known \"[Pythonista](https://en.wiktionary.org/wiki/Pythonista)\" talking about the importance of code style." + "An easier to read version of PEP 8 is [here](https://pep8.org/). The video below features a well known **[Pythonista](https://en.wiktionary.org/wiki/Pythonista)** talking about the importance of code style." ] }, { @@ -1852,7 +1854,7 @@ " " ], "text/plain": [ - "" + "" ] }, "execution_count": 52, @@ -1873,7 +1875,7 @@ } }, "source": [ - "For example, while the above code to calculate the average of the even numbers from `1` through `12` 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](https://docs.python.org/3/library/functions.html) (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." + "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the [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](https://docs.python.org/3/library/functions.html) (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." ] }, { @@ -2075,7 +2077,7 @@ "\n", "At the same time, for a beginner's course, it is often easier to code linearly.\n", "\n", - "In real data science projects, one would probably employ a mixed approach and put 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#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made." + "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made." ] }, { @@ -2097,9 +2099,9 @@ } }, "source": [ - "**Variables** are created with the **[assignment statement](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)** `=`, which is *not* an operator, mainly because of its side effect of making a **[name](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)** point to an object in memory.\n", + "**Variables** are created with the **[assignment statement](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)** `=`, which is *not* an operator, mainly because of its side effect of making a **[name](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)** reference an object in memory.\n", "\n", - "We read the terms **variable**, **name**, and **identifier** used interchangebly in many Python-related texts. In this book, we adopt the following convention: First, we treat *name* and *identifier* as perfect synonyms but only use the term *name* in the text for clarity. Second, whereas *name* only refers to a string of letters, numbers, and some other symbols, a *variable* refers to the combination of a *name* and a *pointer* to some object in memory." + "We read the terms **variable**, **name**, and **identifier** used interchangebly in many Python-related texts. In this book, we adopt the following convention: First, we treat *name* and *identifier* as perfect synonyms but only use the term *name* in the text for clarity. Second, whereas *name* only refers to a string of letters, numbers, and some other symbols, a *variable* means the combination of a *name* and a *reference* to an object in memory." ] }, { @@ -2124,7 +2126,7 @@ } }, "source": [ - "When referenced, a variable evaluates to the value of the object it points to. Colloquially, we could say that `a` evaluates to `20.0`, but this would not be an accurate description of what is going on in memory. We see some more colloquialisms in this section but should always relate this to what Python actually does in memory." + "When used as a *literal*, a variable evaluates to the value of the object it references. Colloquially, we could say that `a` evaluates to `20.0`, but this would not be an accurate description of what is going on in memory. We see some more colloquialisms in this section but should always relate this to what Python actually does in memory." ] }, { @@ -2172,7 +2174,7 @@ }, "outputs": [], "source": [ - "a = 20 # this makes a point to an object of a different type" + "a = 20 # this makes a reference an object of a different type" ] }, { @@ -2281,7 +2283,7 @@ } }, "source": [ - "Variables are **[de-referenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. It does *not* delete the object to which a variable points to but merely removes the variable's name from the \"global list of all names.\"" + "Variables are **[dereferenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. It does *not* delete the object a variable references but merely removes the variable's name from the \"global list of all names.\"" ] }, { @@ -2594,9 +2596,9 @@ } }, "source": [ - "It is *crucial* to understand that *several* variables may point to the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n", + "It is *crucial* to understand that *several* variables may reference the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n", "\n", - "Make `b` point to whatever object `a` is pointing to." + "Make `b` reference whatever object `a` is referencing." ] }, { @@ -2670,7 +2672,7 @@ "source": [ "For \"simple\" types like `int` or `float` this never causes troubles.\n", "\n", - "Let's \"change the value\" of `a`. To be precise, let's create a *new* `123` object and make `a` point to it." + "Let's \"change the value\" of `a`. To be precise, let's create a *new* `123` object and make `a` reference it." ] }, { @@ -2718,7 +2720,7 @@ } }, "source": [ - "`b` \"is still the same\" as before. To be precise, `b` still points to the *same object* as before." + "`b` \"is still the same\" as before. To be precise, `b` still references the *same object* as before." ] }, { @@ -2753,7 +2755,7 @@ } }, "source": [ - "However, if a variable points to an object of a more \"complex\" type (e.g., `list`), \"weird\" things happen." + "However, if a variable references an object of a more \"complex\" type (e.g., `list`), \"weird\" things happen." ] }, { @@ -2816,7 +2818,7 @@ "source": [ "Let's change the first element of `x`.\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of pointers to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the pointer from the global list of all names to the `x` object. Then, it follows the first pointer it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n", "\n", "Note how Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." ] @@ -2853,7 +2855,7 @@ } }, "source": [ - "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable (or overwrite an existing one) but only changes the object to which the first pointer in the `x` list points to. As we only change parts of the `x` object, we say that we **mutate** (i.e., \"change\") its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." + "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable, or overwrite an existing one, but only changes the object which the first element in `x` referenced. As we only change parts of the `x` object, we say that we **mutate** (i.e., \"change\") its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." ] }, { @@ -2901,7 +2903,7 @@ } }, "source": [ - "The changes made to the object `x` is pointing to are also seen through the `y` variable!" + "The changes made to the object `x` is referencing can also be seen through the `y` variable!" ] }, { @@ -2938,11 +2940,11 @@ "source": [ "The illustrated difference in behavior has to do with the fact that integers and floats are **immutable** types while lists are **mutable**.\n", "\n", - "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we did not change the $0$s and $1$s in the object `a` pointed to before the assignment but created a new integer object and made `a` point to it while the `b` variable is *not* affected.\n", + "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we did not change the $0$s and $1$s in the object `a` referenced before the assignment but created a new integer object and made `a` reference it while the `b` variable is *not* affected.\n", "\n", - "In the second case, `x[0] = 99` creates a *new* integer object `99` and merely changes the first pointer in the `x` list.\n", + "In the second case, `x[0] = 99` creates a *new* integer object `99` and merely changes the first reference in the `x` list.\n", "\n", - "In general, the assignment statement creates a new name and makes it point to whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we always must expect that the latter might have more than one variable pointing to it.\n", + "In general, the assignment statement creates a new name and makes it reference whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we always must expect that the latter might have more than one variable referencing it.\n", "\n", "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." ] @@ -3226,7 +3228,7 @@ " " ], "text/plain": [ - "" + "" ] }, "execution_count": 95, @@ -3258,7 +3260,7 @@ } }, "source": [ - "An **[expression](https://docs.python.org/3/reference/expressions.html)** is any syntactically correct **combination** of **variables** and **literals** with **operators**.\n", + "An **[expression](https://docs.python.org/3/reference/expressions.html)** is any syntactically correct *combination* of *variables* and *literals* with *operators*.\n", "\n", "In simple words, anything that may be used on the right-hand side of an assignment statement without creating a `SyntaxError` is an expression.\n", "\n", @@ -3645,7 +3647,7 @@ "source": [ "We use the `#` symbol to write comments in plain English right into the code.\n", "\n", - "As a good practice, comments should not describe *what* happens (this should be evident by reading the code; otherwise, it is most likely badly written code) but *why* something happens.\n", + "As a good practice, comments should *not* describe *what* happens (this should be evident by reading the code; otherwise, it is most likely badly written code) but *why* something happens.\n", "\n", "Comments may be added either at the end of a line of code, by convention separated with two spaces, or on a line on their own." ] @@ -3732,9 +3734,9 @@ "\n", "\n", "- input (examples)\n", - " - (numeric) data from a CSV file\n", + " - data from a CSV file\n", " - text entered on a command line\n", - " - (relational) data obtained from a database\n", + " - data obtained from a database\n", " - etc.\n", "\n", "\n", @@ -3749,20 +3751,20 @@ " - distinct and well-contained areas/parts of the memory that hold the actual data\n", " - the concept by which Python manages the memory for us\n", " - can be classified into objects of the same **type** (i.e., same abstract \"structure\" but different concrete data)\n", - " - built-in objects (incl. **literals**) vs. user-defined objects (cf., Chapter 8)\n", + " - built-in objects (incl. **literals**) vs. user-defined objects (cf., Chapter 9)\n", " - e.g., `1`, `1.0`, and `\"one\"` are three different objects of distinct types that are also literals (i.e., by the way we type them into the command line Python knows what the value and type are)\n", "\n", "\n", "- variables\n", " - storage of intermediate **state**\n", - " - **names** that point to **objects** in **memory**\n", - " - e.g., `x = 1` creates the variable `x` that points to the object `1`\n", + " - are **names** referencing **objects** in **memory**\n", + " - e.g., `x = 1` creates the variable `x` that references the object `1`\n", "\n", "\n", "- operators\n", " - special built-in symbols that perform operations with objects in memory\n", " - usually, operate with one or two objects\n", - " - e.g., addition `+`, subtraction `-`, multiplication `*`, and division `/` all take two objects whereas the negation `-` only takes one\n", + " - e.g., addition `+`, subtraction `-`, multiplication `*`, and division `/` all take two objects, whereas the negation `-` only takes one\n", "\n", "\n", "- expressions\n", @@ -3774,9 +3776,9 @@ "\n", "- statements\n", " - instructions that **\"do\" something** and **have side effects** in memory\n", - " - re-map names to different objects and *change* the state of the program\n", + " - (re-)assign names to (different) objects, *change* an existing object *in place*, or, more conceptually, *change* the state of the program\n", " - usually, work with expressions\n", - " - e.g., the assignment statement `=` makes a name point to an object\n", + " - e.g., the assignment statement `=` makes a name reference an object\n", "\n", "\n", "- comments\n", @@ -3788,6 +3790,7 @@ " - named sequences of instructions\n", " - the smaller parts in a larger program\n", " - make a program more modular and thus easier to understand\n", + " - include [built-in functions](https://docs.python.org/3/library/functions.html) like [print()](https://docs.python.org/3/library/functions.html#print), [sum()](https://docs.python.org/3/library/functions.html#sum), or [len()](https://docs.python.org/3/library/functions.html#len)\n", "\n", "\n", "- flow control (cf., [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb))\n", diff --git a/01_elements_review_and_exercises.ipynb b/01_elements_review_and_exercises.ipynb index 965b8be..21ba4c5 100644 --- a/01_elements_review_and_exercises.ipynb +++ b/01_elements_review_and_exercises.ipynb @@ -138,7 +138,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q7**: \"**dunder**\" refers to a group of Australian (\"down under\") geeks that work on core Python." + "**Q7**: \"**dunder**\" refers to a group of Australian (i.e., \"down under\") geeks that work on core Python." ] }, { @@ -166,7 +166,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q9**: When NASA famously converted some measurements to the wrong unit and lost a Mars satellite in 1999 ([source](https://www.wired.com/2010/11/1110mars-climate-observer-report/)), this is an example of a so-called **runtime error**." + "**Q9**: When NASA famously converted some measurements to the wrong unit and lost a Mars satellite in 1999 (cf., [source](https://www.wired.com/2010/11/1110mars-climate-observer-report/)), this is an example of a so-called **runtime error**." ] }, { diff --git a/02_functions.ipynb b/02_functions.ipynb index 897f8a7..39d7084 100644 --- a/02_functions.ipynb +++ b/02_functions.ipynb @@ -19,9 +19,9 @@ } }, "source": [ - "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Example:-Averaging-Even-Numbers), we typed the code to calculate the average of the even numbers in a list into several 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#Example:-Averaging-Even-Numbers), we typed the code to calculate the average of the even numbers in a list into several code cells. Then, we executed them one after another. We had no way of **reusing** the code except for either executing cells multiple times 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", + "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 reusing the same parts inside core Python every time we use them.\n", "\n", "This chapter shows how Python offers language constructs that let us **define** functions ourselves that we may then **call** just like the built-in ones." ] @@ -45,7 +45,7 @@ } }, "source": [ - "So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** may 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#Best-Practices) 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)** may be created with the `def` statement. To extend an already familiar example, we reuse the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Best-Practices) 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 ordinary variables as Python manages function names like variables. In this book, we further adopt the convention of ending function names with parentheses `()` in text cells for faster comprehension when reading (i.e., `average_evens()` vs. `average_evens`). These are *not* part of the name but must always be written out in the `def` statement for syntactic reasons.\n", "\n", @@ -142,7 +142,7 @@ { "data": { "text/plain": [ - "139646582981088" + "140384699277792" ] }, "execution_count": 3, @@ -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 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." + "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 reference 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." ] }, { @@ -493,7 +493,7 @@ } }, "source": [ - "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%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` 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-20). When the function returns, only the global frame is left (cf., last step)." + "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%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` passed in as the `numbers` argument, there are *two* references 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-20). When the function returns, only the global frame is left (cf., last step)." ] }, { @@ -655,9 +655,9 @@ } }, "source": [ - "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%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 *16* computational steps, namely two for managing the list comprehension, one for setting up an empty `list` object, *twelve* for filling it with elements derived from `nums` in the global scope (i.e., that is the error), and one to make `evens` point at it (cf., steps 6-21).\n", + "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%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 references takes *16* computational steps, namely two for managing the list comprehension, one for setting up an empty `list` object, *twelve* for filling it with elements derived from `nums` in the global scope (i.e., that is the error), and one to make `evens` reference it (cf., steps 6-21).\n", "\n", - "The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Trivial-Example:-Countdown). 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." + "The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Trivial-Example:-Countdown). It is the reason why we may reuse the same names for the parameters and variables inside both `average_evens()` and `average_wrong()` without Python mixing them up. So, as we already read in the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`), and a frame is just a special kind of namespace." ] }, { @@ -822,7 +822,7 @@ } }, "source": [ - "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." + "Python, however, is again smart enough to keep all the involved `nums` variables apart. So, the global `nums` is still referencing the *same* `list` object as before." ] }, { @@ -859,7 +859,7 @@ "source": [ "The reason why everything 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,%2011,%2012%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", + "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%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 referencing *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", @@ -1124,7 +1124,7 @@ } }, "source": [ - "We may also go in the other direction with the [float()](https://docs.python.org/3/library/functions.html#float) built-in function." + "We may also go in the other direction with the [float()](https://docs.python.org/3/library/functions.html#float) built-in." ] }, { @@ -1432,9 +1432,9 @@ "source": [ "Defining both `average_evens()` and `scaled_average_evens()` is also kind of repetitive as most of their code is the same. Such a redundancy makes a codebase harder to maintain in the long run as whenever we change the logic in one function, we must *not* forget to do so for the other function as well.\n", "\n", - "A better way is to design related functions in a **modular** fashion such that they re-use each other's logic.\n", + "A better way is to design related functions in a **modular** fashion such that they reuse each other's logic.\n", "\n", - "For example, as not scaling an average is just a special case of scaling it with `1`, we could re-define the two functions like below: In this setting, the function resembling the *special* case (i.e., `average_evens()`) **forwards** the call to the more *general* function (i.e., `scaled_average_evens()`) using a `scalar=1` argument." + "For example, as not scaling an average is just a special case of scaling it with `1`, we could redefine the two functions like below: In this setting, the function resembling the *special* case (i.e., `average_evens()`) **forwards** the call to the more *general* function (i.e., `scaled_average_evens()`) using a `scalar=1` argument." ] }, { @@ -1796,17 +1796,17 @@ } }, "source": [ - "The `def` statement is a statement because of its side effect of creating a *new* name that points to a *new* `function` object in memory.\n", + "The `def` statement is a statement because of its side effect of creating a *new* name that references a *new* `function` object in memory.\n", "\n", - "We can thus think of it as doing *two* things at once (i.e., either both of them happen or none). First, a `function` object is created that contains the concrete $0$s and $1$s that resemble the instructions we put into the function's body. In the context of a function, these $0$s and $1$s are also called **[byte code](https://en.wikipedia.org/wiki/Bytecode)**. Then, a name pointing at the new `function` object is created.\n", + "We can thus think of it as doing *two* things at once (i.e., either both of them happen or none). First, a `function` object is created that contains the concrete $0$s and $1$s that resemble the instructions we put into the function's body. In the context of a function, these $0$s and $1$s are also called **[byte code](https://en.wikipedia.org/wiki/Bytecode)**. Then, a name referencing the new `function` object is created.\n", "\n", "Only this second aspect makes `def` a statement: Merely creating a new object in memory without making it accessible for later reference does *not* constitute a side effect because the state the program is *not* changed. After all, if we cannot reference an object, how do we know it exists in the first place?\n", "\n", - "Python provides a so-called **[lambda expression](https://docs.python.org/3/reference/expressions.html#lambda)** syntax that allows us to *only* create a `function` object in memory *without* making a name point to it.\n", + "Python provides a so-called **[lambda expression](https://docs.python.org/3/reference/expressions.html#lambda)** syntax that allows us to *only* create a `function` object in memory *without* making a name reference it.\n", "\n", "It starts with the keyword `lambda` followed by an optional comma separated enumeration of parameters, a mandatory colon, and *one* expression that also is the resulting `function` object's return value.\n", "\n", - "Because it does not create a name pointing to the object, we effectively create \"anonymous\" functions with it. In the example, we create a `function` object that adds `3` to the only argument passed in as the parameter `x` and returns that sum." + "Because it does not create a name referencing the object, we effectively create \"anonymous\" functions with it. In the example, we create a `function` object that adds `3` to the only argument passed in as the parameter `x` and returns that sum." ] }, { @@ -1965,9 +1965,9 @@ "source": [ "So far, we have only used what we refer to as **core** Python in this book. By this, we mean all the syntactical rules as specified in the [language reference](https://docs.python.org/3/reference/) and a minimal set of about 50 built-in [functions](https://docs.python.org/3/library/functions.html). With this, we could already implement any algorithm or business logic we can think of!\n", "\n", - "However, after our first couple of programs, we would already start seeing recurring patterns in the code we write. In other words, we would constantly be \"re-inventing the wheel\" in each new project.\n", + "However, after our first couple of programs, we would already start seeing recurring patterns in the code we write. In other words, we would constantly be \"reinventing the wheel\" in each new project.\n", "\n", - "Would it not be smarter to pull out the re-usable components from our programs and put them into some project independent **library** of generically useful functionalities? Then we would only need a way of including these **utilities** in our projects.\n", + "Would it not be smarter to pull out the reusable components from our programs and put them into some project independent **library** of generically useful functionalities? Then we would only need a way of including these **utilities** in our projects.\n", "\n", "As all programmers across all languages face this very same issue, most programming languages come with a so-called **[standard library](https://en.wikipedia.org/wiki/Standard_library)** that provides utilities to accomplish everyday tasks without much code. Examples are making an HTTP request to some website, open and read popular file types (e.g., CSV or Excel files), do something on a computer's file system, and many more." ] @@ -1993,7 +1993,7 @@ "source": [ "Python also comes with a [standard library](https://docs.python.org/3/library/index.html) that is structured into coherent modules and packages for given topics: A **module** is just a plain text file with the file extension *.py* that contains Python code while a **package** is a folder that groups several related modules.\n", "\n", - "The code in the [standard library](https://docs.python.org/3/library/index.html) is contributed and maintained by many volunteers around the world. In contrast to so-called \"third-party\" packages (cf., the next section below), the Python core development team closely monitors and tests the code in the [standard library](https://docs.python.org/3/library/index.html). Consequently, we can be reasonably sure that anything provided by it works correctly independent of our computer's operating system and will most likely also be there in the next Python versions. Parts in the [standard library](https://docs.python.org/3/library/index.html) that are computationally expensive are often re-written in C and, therefore, much faster than anything we could write in Python ourselves. So, whenever we can solve a problem with the help of the [standard library](https://docs.python.org/3/library/index.html), it is almost always the best way to do so as well.\n", + "The code in the [standard library](https://docs.python.org/3/library/index.html) is contributed and maintained by many volunteers around the world. In contrast to so-called \"third-party\" packages (cf., the next section below), the Python core development team closely monitors and tests the code in the [standard library](https://docs.python.org/3/library/index.html). Consequently, we can be reasonably sure that anything provided by it works correctly independent of our computer's operating system and will most likely also be there in the next Python versions. Parts in the [standard library](https://docs.python.org/3/library/index.html) that are computationally expensive are often rewritten in C and, therefore, much faster than anything we could write in Python ourselves. So, whenever we can solve a problem with the help of the [standard library](https://docs.python.org/3/library/index.html), it is almost always the best way to do so as well.\n", "\n", "The [standard library](https://docs.python.org/3/library/index.html) has grown very big over the years, and we refer to the website [PYMOTW](https://pymotw.com/3/index.html) (i.e., \"Python Module of the Week\") that features well written introductory tutorials and how-to guides to most parts of the library. The same author also published a [book](https://www.amazon.com/Python-Standard-Library-Example-Developers/dp/0134291050/ref=as_li_ss_tl?ie=UTF8&qid=1493563121&sr=8-1&keywords=python+3+standard+library+by+example) that many Pythonistas keep on their shelf for reference. Knowing what is in the [standard library](https://docs.python.org/3/library/index.html) is quite valuable for solving real-world tasks quickly.\n", "\n", @@ -2045,7 +2045,7 @@ } }, "source": [ - "This creates the variable `math` that points to a **[module object](https://docs.python.org/3/glossary.html#term-module)** (i.e., type `module`) in memory." + "This creates the variable `math` that references a **[module object](https://docs.python.org/3/glossary.html#term-module)** (i.e., type `module`) in memory." ] }, { @@ -2084,7 +2084,7 @@ { "data": { "text/plain": [ - "139646755983752" + "140384754610488" ] }, "execution_count": 58, @@ -2430,7 +2430,7 @@ "source": [ "If we only need one particular function from a module, we may also use the alternative `from ... import ...` syntax.\n", "\n", - "This does *not* create a module object but only makes a variable in our current location point to an object defined inside a module directly." + "This does *not* create a module object but only makes a variable in our current location reference an object defined inside a module directly." ] }, { @@ -2697,7 +2697,7 @@ { "data": { "text/plain": [ - "0.21932911318720072" + "0.17184403163109208" ] }, "execution_count": 75, @@ -2732,7 +2732,7 @@ { "data": { "text/plain": [ - ">" + ">" ] }, "execution_count": 76, @@ -2781,7 +2781,7 @@ { "data": { "text/plain": [ - "7" + "2" ] }, "execution_count": 78, @@ -3242,7 +3242,7 @@ "\n", "The *name* to be imported is the file's name except for the *.py* part. For this to work, the file's name *must* adhere to the *same* rules as hold for [variable names](https://docs.python.org/3/reference/lexical_analysis.html#identifiers) in general.\n", "\n", - "What happens during an import is as follows. When Python sees the `import sample_module` part, it first creates a *new* object of type `module` in memory. This is effectively an *empty* namespace. Then, it executes the imported file's code from top to bottom. Whatever variables are still defined at the end of this, are put into the module's namespace. Only if the file's code does *not* raise an error, will Python make a variable in our current location (i.e., `mod` here) point to the created `module` object. Otherwise, it is discarded. In essence, it is as if we copied and pasted the file's code in place of the import statement. If we import an already imported module again, Python is smart enough to avoid doing all this work all over and does nothing." + "What happens during an import is as follows. When Python sees the `import sample_module` part, it first creates a *new* object of type `module` in memory. This is effectively an *empty* namespace. Then, it executes the imported file's code from top to bottom. Whatever variables are still defined at the end of this, are put into the module's namespace. Only if the file's code does *not* raise an error, will Python make a variable in our current location (i.e., `mod` here) reference the created `module` object. Otherwise, it is discarded. In essence, it is as if we copied and pasted the file's code in place of the import statement. If we import an already imported module again, Python is smart enough to avoid doing all this work all over and does nothing." ] }, { @@ -3341,7 +3341,7 @@ } }, "source": [ - "We use the imported `mod.average_evens()` just like `average_evens()` defined above. The advantage we get from **modularization** with *.py* files is that we can now easily re-use functions across different Jupyter notebooks without re-defining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook." + "We use the imported `mod.average_evens()` just like `average_evens()` defined above. The advantage we get from **modularization** with *.py* files is that we can now easily reuse functions across different Jupyter notebooks without redefining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook." ] }, { @@ -3462,7 +3462,7 @@ "Functions provide benefits as they:\n", "\n", "- make programs easier to comprehend and debug for humans as they give names to the smaller parts of a larger program (i.e., they **modularize** a codebase), and\n", - "- eliminate redundancies by allowing **re-use of code**.\n", + "- eliminate redundancies by allowing **reuse of code**.\n", "\n", "Functions are **defined** once with the `def` statement. Then, they may be **called** many times with the call operator `()`.\n", "\n", diff --git a/02_functions_review_and_exercises.ipynb b/02_functions_review_and_exercises.ipynb index d0935c6..ca631a7 100644 --- a/02_functions_review_and_exercises.ipynb +++ b/02_functions_review_and_exercises.ipynb @@ -215,21 +215,27 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "import ..." + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "r = ..." + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "..." + ] }, { "cell_type": "markdown", @@ -244,17 +250,8 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "def sphere_volume(...):\n", + " ..." ] }, { @@ -269,42 +266,54 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "radius = ..." + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "sphere_volume(...)" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "sphere_volume(...)" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "sphere_volume(...)" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "sphere_volume(...)" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "sphere_volume(...)" + ] }, { "cell_type": "markdown", @@ -334,7 +343,9 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "radius = ..." + ] }, { "cell_type": "code", @@ -342,14 +353,15 @@ "metadata": {}, "outputs": [], "source": [ - "\n" + "for ... in ...:\n", + " ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Q11.6**: What lesson did you learn about the `float` type?" + "**Q11.6**: What lesson do you learn about the `float` type?" ] }, { diff --git a/03_conditionals.ipynb b/03_conditionals.ipynb index 072448a..9ffe09e 100644 --- a/03_conditionals.ipynb +++ b/03_conditionals.ipynb @@ -19,7 +19,7 @@ } }, "source": [ - "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` related parts. While it seems to do what we expect it to, there is a whole lot more we learn from taking it apart. In particular, the `if` may occur within both a **statement** or an **expression**, analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both usages is that it leads to code being executed for *parts* of the input only. It is 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`-related parts. While it seems to do what we expect it to, there is a whole lot more we learn from taking it apart. In particular, the `if` may occur within both a **statement** or an **expression**, analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both usages is that it leads to code being executed for *parts* of the input only. It is 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 **exceptions**." ] @@ -189,7 +189,7 @@ { "data": { "text/plain": [ - "94711290794976" + "93918328484832" ] }, "execution_count": 5, @@ -213,7 +213,7 @@ { "data": { "text/plain": [ - "94711290794944" + "93918328484800" ] }, "execution_count": 6, @@ -313,7 +313,7 @@ { "data": { "text/plain": [ - "94711290781936" + "93918328471792" ] }, "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#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", + "`True`, `False`, and `None` have the property that they each exist in memory only *once*. Objects designed this way are so-called **singletons**. This **[design pattern](https://en.wikipedia.org/wiki/Design_Patterns)** was originally developed to keep a program's memory usage at a minimum. It may only be employed in situations where we know that an object does *not* mutate its value (i.e., to reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/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." ] @@ -418,7 +418,7 @@ } }, "source": [ - "So the following expression regards *four* objects in memory: *One* `list` object holding ten pointers to *three* other objects." + "So the following expression regards *four* objects in memory: *One* `list` object holding ten references to *three* other objects." ] }, { diff --git a/03_conditionals_review_and_exercises.ipynb b/03_conditionals_review_and_exercises.ipynb index 89d7009..90b4ff9 100644 --- a/03_conditionals_review_and_exercises.ipynb +++ b/03_conditionals_review_and_exercises.ipynb @@ -110,7 +110,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q6**: What does the `finally`-branch enforce in this code snippet? How can a `try` statement be useful *without* an `except`-branch?" + "**Q6**: What does the `finally`-clause enforce in this code snippet? How can a `try` statement be useful *without* an `except`-clause?" ] }, { @@ -210,22 +210,8 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "def discounted_price(...):\n", + " ..." ] }, { @@ -279,7 +265,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q9.3**: Re-calculate the last two line items with order quantities of $20$ and $15$. What do you observe?" + "**Q9.3**: Calculate the last two line items with order quantities of $20$ and $15$. What do you observe?" ] }, { @@ -304,7 +290,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " (your observation)" + " " ] }, { @@ -373,12 +359,6 @@ "outputs": [], "source": [ "for number in numbers:\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", " ..." ] }, diff --git a/04_iteration.ipynb b/04_iteration.ipynb index 2246da5..aabaaef 100644 --- a/04_iteration.ipynb +++ b/04_iteration.ipynb @@ -91,7 +91,7 @@ " Args:\n", " n (int): seconds until the party begins\n", " \"\"\"\n", - " if n == 0: # base case\n", + " if n == 0: # = base case\n", " print(\"Happy New Year!\")\n", " else:\n", " print(n)\n", @@ -222,7 +222,7 @@ " Returns:\n", " factorial (int)\n", " \"\"\"\n", - " if n == 0:\n", + " if n == 0: # = base case\n", " return 1\n", " else:\n", " recurse = factorial(n - 1)\n", @@ -323,7 +323,7 @@ " Returns:\n", " factorial (int)\n", " \"\"\"\n", - " if n == 0:\n", + " if n == 0: # = base case\n", " return 1\n", " return n * factorial(n - 1)" ] @@ -517,7 +517,7 @@ " Returns:\n", " gcd (int)\n", " \"\"\"\n", - " if b == 0:\n", + " if b == 0: # = base case\n", " return a \n", " return gcd(b, a % b)" ] @@ -787,9 +787,9 @@ " Returns:\n", " ith_fibonacci (int)\n", " \"\"\"\n", - " if i == 0:\n", + " if i == 0: # = first base case\n", " return 0\n", - " elif i == 1:\n", + " elif i == 1: # = second base case\n", " return 1\n", " return fibonacci(i - 1) + fibonacci(i - 2)" ] @@ -841,7 +841,7 @@ "\n", "To understand this in detail, we would have to study algorithms and data structures (e.g., with [this book](https://www.amazon.de/Introduction-Algorithms-Press-Thomas-Cormen/dp/0262033844/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=1JNE8U0VZGU0O&qid=1569837169&s=gateway&sprefix=algorithms+an%2Caps%2C180&sr=8-1)), a discipline within computer science, and dive into the analysis of **[time complexity of algorithms](https://en.wikipedia.org/wiki/Time_complexity)**.\n", "\n", - "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"re-use\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in Chapter 8, after introducing the [dictionaries](https://docs.python.org/3/library/stdtypes.html#dict) data type.\n", + "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings.ipynb#Memoization), after introducing the [dictionaries](https://docs.python.org/3/library/stdtypes.html#dict) data type.\n", "\n", "Let's measure the average run times for `fibonacci()` and varying `i` arguments with the `%%timeit` [cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit) that comes with Jupyter." ] @@ -859,7 +859,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "36.5 µs ± 2.47 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "37.5 µs ± 4.26 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -881,7 +881,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "1.58 ms ± 20.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "1.49 ms ± 22.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -903,7 +903,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "194 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "199 ms ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -925,7 +925,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "2.15 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "2.04 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -947,7 +947,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "5.59 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "5.33 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -4011,9 +4011,9 @@ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcountdown\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\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\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[1;32m 10\u001b[0m \u001b[0mprint\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[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\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\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\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[1;32m 10\u001b[0m \u001b[0mprint\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[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "... last 1 frames repeated, from the frame below ...\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\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[1;32m 10\u001b[0m \u001b[0mprint\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[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\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\u001b[0m in \u001b[0;36mcountdown\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 9\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[1;32m 10\u001b[0m \u001b[0mprint\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[0;32m---> 11\u001b[0;31m \u001b[0mcountdown\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded while calling a Python object" ] } @@ -4050,9 +4050,9 @@ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\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\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\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[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\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\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\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;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "... last 1 frames repeated, from the frame below ...\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\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[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\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\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 10\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;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 12\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison" ] } @@ -4143,7 +4143,7 @@ " raise TypeError(\"Factorial is only defined for integers\")\n", " elif 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)" ] @@ -4235,7 +4235,7 @@ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\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\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\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[0;32m---> 15\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 16\u001b[0m \u001b[0;32melif\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[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 13\u001b[0m \"\"\"\n\u001b[1;32m 14\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\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[0;32m---> 15\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 16\u001b[0m \u001b[0;32melif\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[1;32m 17\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative integers\"\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" ] } @@ -4261,7 +4261,7 @@ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfactorial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m42\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\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \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[1;32m 16\u001b[0m \u001b[0;32melif\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---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative 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 18\u001b[0m \u001b[0;32melif\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[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mfactorial\u001b[0;34m(n)\u001b[0m\n\u001b[1;32m 15\u001b[0m \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[1;32m 16\u001b[0m \u001b[0;32melif\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---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Factorial is not defined for negative 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 18\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# = base case\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: Factorial is not defined for negative integers" ] } @@ -4565,7 +4565,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "4.69 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "4.6 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -4790,11 +4790,11 @@ } }, "source": [ - "Recursion and the `while` statement are two sides of the same coin. Disregarding that in the case of recursion Python internally faces some additional burden for managing the stack of frames in memory, both approaches lead to the *same* computational steps in memory. More importantly, we can re-formulate a recursive implementation in an iterative way and vice versa despite one of the two ways often \"feeling\" a lot more natural given a particular problem.\n", + "Recursion and the `while` statement are two sides of the same coin. Disregarding that in the case of recursion Python internally faces some additional burden for managing the stack of frames in memory, both approaches lead to the *same* computational steps in memory. More importantly, we can formulate any recursive implementation in an iterative way and vice versa despite one of the two ways often \"feeling\" a lot more natural given a particular problem.\n", "\n", "So how does the compound `for` statement (cf., [reference](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement)) in this book's very first example fit into this picture? It is a *redundant* language construct to provide a *shorter* and more *convenient* syntax for common applications of the `while` statement. In programming, such additions to a language are called **syntactic sugar**. A cup of tea tastes better with sugar, but we may drink tea without sugar too.\n", "\n", - "Consider `elements` below. Without the `for` statement, we have to manage a temporary **index variable**, `index`, to loop over all the elements and also obtain the individual elements with the `[]` operator in each iteration of the loop." + "Consider `elements` below. Without the `for` statement, we must manage a temporary **index variable**, `index`, to loop over all the elements and also obtain the individual elements with the `[]` operator in each iteration of the loop." ] }, { @@ -5000,21 +5000,21 @@ } }, "source": [ - "The essential difference between the above `list` objects, `[0, 1, 2, 3, 4]` and `[1, 3, 5, 7, 9]`, and the `range` objects, `range(5)` and `range(1, 10, 2)`, is that in the former case *six* objects are created in memory *before* the `for` statement starts running, *one* `list` holding pointers to *five* `int` objects, whereas in the latter case only *one* `range` object is created that **generates** `int` objects one at a time *while* the `for`-loop runs.\n", + "The essential difference between the above `list` objects, `[0, 1, 2, 3, 4]` and `[1, 3, 5, 7, 9]`, and the `range` objects, `range(5)` and `range(1, 10, 2)`, is that in the former case *six* objects are created in memory *before* the `for` statement starts running, *one* `list` holding references to *five* `int` objects, whereas in the latter case only *one* `range` object is created that **generates** `int` objects one at a time *while* the `for`-loop runs.\n", "\n", "However, we can loop over both of them. So a natural question to ask is why Python treats objects of *different* types in the *same* way when used with a `for` statement.\n", "\n", - "So far, the overarching storyline in this book goes like this: In Python, *everything* is an object. Besides its *identity* and *value*, every object is characterized by belonging to *one data type* that determines how the object behaves and what we may do with it.\n", + "So far, the overarching storyline in this book goes like this: In Python, *everything* is an object. Besides its *identity* and *value*, every object is characterized by \"belonging\" to *one* data type that determines how the object behaves and what we may do with it.\n", "\n", - "Now, just as we classify objects by their types, we also classify these **concrete data types** (e.g., `int`, `float`, `str`, or `list`) into **abstract concepts**.\n", + "Now, just as we classify objects by data type, we also classify these data types (e.g., `int`, `float`, `str`, or `list`) into **abstract concepts**.\n", "\n", - "We did this already in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?) when we described a `list` object as \"some sort of container that holds [...] pointers to other objects\". So, abstractly speaking, **containers** are any objects that are \"composed\" of other objects and also \"manage\" how these objects are organized. `list` objects, for example, have the property that they model an internal order associated with its elements. There exist, however, other container types, many of which do *not* come with an order. So, containers primarily \"contain\" other objects and have *nothing* to do with looping.\n", + "We did this already in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?) when we described a `list` object as \"some sort of container that holds [...] references to other objects\". So, abstractly speaking, **containers** are any objects that are \"composed\" of other objects and also \"manage\" how these objects are organized. `list` objects, for example, have the property that they model an order associated with their elements. There exist, however, other container types, many of which do *not* come with an order. So, containers primarily \"contain\" other objects and have *nothing* to do with looping.\n", "\n", - "On the contrary, the abstract concept of **iterables** is all about looping: Any object that we can loop over is, by definition, an iterable. So, `range` objects, for example, are iterables that do *not* contain other objects. Moreover, looping does *not* have to occur in a *predictable* order, although this is the case for both `list` and `range` objects.\n", + "On the contrary, the abstract concept of **iterables** is all about looping: Any object that we can loop over is, by definition, an iterable. So, `range` objects, for example, are iterables, even though they hold no references to other objects. Moreover, looping does *not* have to occur in a *predictable* order, although this is the case for both `list` and `range` objects.\n", "\n", - "Typically, containers are iterables, and iterables are containers. Yet, only because these two concepts coincide often, we must not think of them as the same. Chapter 9 finally gives an explanation as to how abstract concepts are implemented and play together.\n", + "Typically, containers are iterables, and iterables are containers. Yet, only because these two concepts coincide often, we must not think of them as the same. In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#Collections-vs.-Sequences), we formalize these two concepts and introduce many more. Finally, Chapter 9 gives an explanation how abstract concepts are implemented and play together.\n", "\n", - "So, `list` objects like `first_names` below are iterable containers. They implement even more abstract concepts, as [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#Collections-vs.-Sequences) reveals." + "Let's continue with `first_names` below as an example an illustrate what iterable containers are." ] }, { @@ -5038,7 +5038,7 @@ } }, "source": [ - "The characteristic operator associated with a container type is the `in` operator: It checks if a given object evaluates equal to at least one of the objects in the container. Colloquially, it checks if an object is \"contained\" in the container. Formally, this operation is called **membership testing**." + "The characteristic operator associated with container types is the `in` operator: It checks if a given object evaluates equal to at least one of the objects in the container. Colloquially, it checks if an object is \"contained\" in the container. Formally, this operation is called **membership testing**." ] }, { @@ -5112,7 +5112,7 @@ { "data": { "text/plain": [ - "True" + "[0, 1, 2, 3, 4]" ] }, "execution_count": 58, @@ -5120,6 +5120,30 @@ "output_type": "execute_result" } ], + "source": [ + "elements" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "3.0 in elements" ] @@ -5137,7 +5161,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 60, "metadata": { "slideshow": { "slide_type": "slide" @@ -5170,7 +5194,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5203,7 +5227,7 @@ }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "skip" @@ -5236,7 +5260,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "skip" @@ -5249,7 +5273,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "skip" @@ -5297,7 +5321,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 65, "metadata": { "code_folding": [], "slideshow": { @@ -5338,7 +5362,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "slide" @@ -5358,7 +5382,7 @@ "144" ] }, - "execution_count": 65, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -5391,7 +5415,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 67, "metadata": { "slideshow": { "slide_type": "slide" @@ -5411,7 +5435,7 @@ "218922995834555169026" ] }, - "execution_count": 66, + "execution_count": 67, "metadata": {}, "output_type": "execute_result" } @@ -5444,7 +5468,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 68, "metadata": { "slideshow": { "slide_type": "slide" @@ -5480,7 +5504,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "slide" @@ -5500,7 +5524,7 @@ "3628800" ] }, - "execution_count": 68, + "execution_count": 69, "metadata": {}, "output_type": "execute_result" } @@ -5555,7 +5579,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "slide" @@ -5568,7 +5592,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "-" @@ -5592,7 +5616,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5638,7 +5662,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "slide" @@ -5716,7 +5740,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "slide" @@ -5759,7 +5783,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "slide" @@ -5797,7 +5821,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "skip" @@ -5885,7 +5909,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 77, "metadata": { "slideshow": { "slide_type": "slide" @@ -5898,7 +5922,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "-" @@ -5918,7 +5942,7 @@ "370" ] }, - "execution_count": 77, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -5980,7 +6004,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "slide" @@ -5993,7 +6017,7 @@ "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" ] }, - "execution_count": 78, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -6004,7 +6028,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "-" @@ -6024,7 +6048,7 @@ "227" ] }, - "execution_count": 79, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -6070,7 +6094,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "slide" @@ -6090,7 +6114,7 @@ "227" ] }, - "execution_count": 80, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -6178,7 +6202,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "slide" @@ -6191,7 +6215,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "-" @@ -6204,7 +6228,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 84, "metadata": { "code_folding": [], "slideshow": { @@ -6283,7 +6307,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" @@ -6320,7 +6344,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 86, "metadata": { "slideshow": { "slide_type": "slide" @@ -6358,7 +6382,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 87, "metadata": { "slideshow": { "slide_type": "skip" @@ -6371,7 +6395,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 88, "metadata": { "slideshow": { "slide_type": "slide" @@ -6441,7 +6465,7 @@ "\n", "Second, the `while` and `for` statements are alternative and potentially more intuitive ways to express iteration as they correspond to a **forward** reasoning. The `for` statement is **syntactic sugar** that allows rewriting common occurrences of the `while` statement concisely. Python provides the `break` and `continue` statements as well as an optional `else`-clause that make working with the `for` and `while` statements even more convenient.\n", "\n", - "**Iterables** are any **concrete data types** that support being looped over, for example, with the `for` statement. The idea behind iterables is an **abstract concept** that may or may not be implemented by any given concrete data type. For example, both `list` and `range` objects can be looped over. The `list` type is also a **container** as any given `list` objects \"contains\" pointers to other objects in memory. On the contrary, the `range` type does not point to any other objects but instead creates *new* `int` objects \"on the fly\" (i.e., when being looped over)." + "**Iterables** are any **concrete data types** that support being looped over, for example, with the `for` statement. The idea behind iterables is an **abstract concept** that may or may not be implemented by any given concrete data type. For example, both `list` and `range` objects can be looped over. The `list` type is also a **container** as any given `list` objects \"contains\" references to other objects in memory. On the contrary, the `range` type does not reference any other object but instead creates *new* `int` objects \"on the fly\" (i.e., when being looped over)." ] } ], diff --git a/04_iteration_review_and_exercises.ipynb b/04_iteration_review_and_exercises.ipynb index 64d6903..9e2b28f 100644 --- a/04_iteration_review_and_exercises.ipynb +++ b/04_iteration_review_and_exercises.ipynb @@ -455,19 +455,8 @@ "\n", " # answer to Q15.6\n", " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", - " # ...\n", "\n", " # answer to Q15.7\n", - " # ...\n", " # ..." ] }, @@ -543,7 +532,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Pythonic Re-Factoring" + "#### Pythonic Refactoring" ] }, { @@ -569,7 +558,6 @@ " # ...\n", "\n", " # answer to Q15.10\n", - " # ...\n", " # ..." ] }, @@ -726,7 +714,8 @@ "metadata": {}, "outputs": [], "source": [ - "\n" + "for ... in ...:\n", + " ..." ] }, { @@ -811,9 +800,9 @@ " if offset is not None:\n", " count += offset\n", "\n", - " hanoi_ordered(..., offset=offset) # <- answer to Q15.18 between the ()\n", - " # answer to Q15.18\n", - " hanoi_ordered(..., offset=count) # <- answer to Q15.18 between the ()" + " hanoi_ordered(..., offset=offset) # <- answer to Q15.18\n", + " # ... <- answer to Q15.18\n", + " hanoi_ordered(..., offset=count) # <- answer to Q15.18" ] }, { diff --git a/05_numbers.ipynb b/05_numbers.ipynb index a671e68..48d8623 100644 --- a/05_numbers.ipynb +++ b/05_numbers.ipynb @@ -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\u001b[0m in \u001b[0;36m\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\u001b[0m in \u001b[0;36m\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\u001b[0m in \u001b[0;36m\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\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\u001b[0m in \u001b[0;36m\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\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\u001b[0m in \u001b[0;36m\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\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\u001b[0m in \u001b[0;36m\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\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." ] } ], diff --git a/05_numbers_review_and_exercises.ipynb b/05_numbers_review_and_exercises.ipynb index 90983d4..2ae8301 100644 --- a/05_numbers_review_and_exercises.ipynb +++ b/05_numbers_review_and_exercises.ipynb @@ -156,7 +156,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q9**: How can **abstract data types**, for example, as defined in the **numerical tower**, be helpful in enabling **duck typing**?" + "**Q9**: How can **abstract base classes**, for example, as defined in the **numerical tower**, be helpful in enabling **duck typing**?" ] }, { @@ -519,7 +519,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q19.7**: Re-write the function `discounted_price()` from [Chapter 3's Review & Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_review_and_exercises.ipynb#Discounting-Customer-Orders) section!\n", + "**Q19.7**: Rewrite the function `discounted_price()` from [Chapter 3's Review & Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_review_and_exercises.ipynb#Discounting-Customer-Orders) section!\n", "\n", "It takes the *positional* arguments `unit_price` and `quantity` and implements a discount scheme for a line item in a customer order as follows:\n", "\n", @@ -530,7 +530,7 @@ "\n", "The function then returns the overall price for the line item as a `Decimal` number with a precision of *two* decimals.\n", "\n", - "Enable **duck typing** by allowing the function to be called with various numeric types as the arguments, in particular, `quantity` may be a non-integer as well: Use an appropriate **abstract data type** from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to verify the arguments' types and also that they are both positive!\n", + "Enable **duck typing** by allowing the function to be called with various numeric types as the arguments, in particular, `quantity` may be a non-integer as well: Use an appropriate **abstract base class** from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to verify the arguments' types and also that they are both positive!\n", "\n", "It is considered a *best practice* to only round towards the *end* of the calculations." ] @@ -551,22 +551,6 @@ "outputs": [], "source": [ "def discounted_price(...):\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", - " ...\n", " ..." ] }, diff --git a/06_text.ipynb b/06_text.ipynb index 44eaa3c..3fbbcb5 100644 --- a/06_text.ipynb +++ b/06_text.ipynb @@ -54,7 +54,7 @@ }, "outputs": [], "source": [ - "school = \"WHU - Otto Beisheim School of Management\"" + "text = \"Lorem ipsum dolor sit amet, consectetur ...\"" ] }, { @@ -65,7 +65,7 @@ } }, "source": [ - "Like everything in Python, `school` is an object." + "Like everything in Python, `text` is an object." ] }, { @@ -80,7 +80,7 @@ { "data": { "text/plain": [ - "140488988107952" + "139674889049360" ] }, "execution_count": 2, @@ -89,7 +89,7 @@ } ], "source": [ - "id(school)" + "id(text)" ] }, { @@ -113,7 +113,7 @@ } ], "source": [ - "type(school)" + "type(text)" ] }, { @@ -141,7 +141,7 @@ { "data": { "text/plain": [ - "'WHU - Otto Beisheim School of Management'" + "'Lorem ipsum dolor sit amet, consectetur ...'" ] }, "execution_count": 4, @@ -150,7 +150,7 @@ } ], "source": [ - "school" + "text" ] }, { @@ -182,7 +182,7 @@ { "data": { "text/plain": [ - "\"It's cool that strings are so versatile in Python!\"" + "\"It's cool that strings are so versatile!\"" ] }, "execution_count": 5, @@ -191,7 +191,7 @@ } ], "source": [ - "\"It's cool that strings are so versatile in Python!\"" + "\"It's cool that strings are so versatile!\"" ] }, { @@ -206,7 +206,7 @@ { "data": { "text/plain": [ - "\"It's cool that strings are so versatile in Python!\"" + "\"It's cool that strings are so versatile!\"" ] }, "execution_count": 6, @@ -215,7 +215,7 @@ } ], "source": [ - "'It\\'s cool that strings are so versatile in Python!'" + "'It\\'s cool that strings are so versatile!'" ] }, { @@ -623,7 +623,7 @@ "execution_count": 20, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -660,7 +660,7 @@ "execution_count": 21, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -737,7 +737,7 @@ } }, "source": [ - "A **sequence** is yet another *abstract* concept (cf., *containers* and *iterables* in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables)).\n", + "A **sequence** is yet another *abstract* concept (cf., the \"*Containers vs. Iterables*\" section in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables)).\n", "\n", "It unifies *four* [orthogonal](https://en.wikipedia.org/wiki/Orthogonality) (i.e., \"independent\") behaviors into one idea: Any data type, such as `str`, is considered a sequence if it simultaneously\n", "\n", @@ -748,7 +748,7 @@ "\n", "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#Collections-vs.-Sequences) formalizes sequences in great detail. Here, we keep our focus on the `str` type that historically received its name as it models a \"**[string of characters](https://en.wikipedia.org/wiki/String_%28computer_science%29)**,\" and a \"string\" is more formally called a sequence in the computer science literature.\n", "\n", - "Behaving like a sequence, `str` objects may be treated like `list` objects in many cases. For example, the built-in [len()](https://docs.python.org/3/library/functions.html#len) function tells us how many elements (i.e., characters) make up `school`. [len()](https://docs.python.org/3/library/functions.html#len) would not work on an \"*infinite*\" object: As anything modeled in a program must fit into a computer's finite memory at runtime, there cannot exist objects containing a truly infinite number of elements; however, [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#Collections-vs.-Sequences#Mapping) introduces *concrete* iterable data types that can be used to model an *infinite* series of elements and that, consequently, have no concept of \"length.\"" + "Behaving like a sequence, `str` objects may be treated like `list` objects in many cases. For example, the built-in [len()](https://docs.python.org/3/library/functions.html#len) function tells us how many elements (i.e., characters) make up `text`. [len()](https://docs.python.org/3/library/functions.html#len) would not work with an *infinite* object: As anything modeled in a program must fit into a computer's finite memory at runtime, there cannot exist objects containing a truly infinite number of elements; however, [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences.ipynb#Iterators-vs.-Iterables) introduces iterable data types that can be used to model an *infinite* series of elements and that, consequently, have no concept of \"length.\"" ] }, { @@ -763,7 +763,7 @@ { "data": { "text/plain": [ - "40" + "43" ] }, "execution_count": 23, @@ -772,7 +772,7 @@ } ], "source": [ - "len(school)" + "len(text)" ] }, { @@ -783,9 +783,7 @@ } }, "source": [ - "Being iterable, we can iterate over a `str` object, for example, with a `for`-loop, and do something with the individual characters, for example, print them out with extra space in between them.\n", - "\n", - "[Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables) already shows that we can loop over *different* concrete types: The example there first loops over the `list` object `[0, 1, 2, 3, 4]` and then the `range` object `range(5)`, with the same outcome. Now, we add the `str` type to the list of *concrete* types we can loop over. *Abstractly* speaking, all three are *iterable*, and there are many more iterable types in Python." + "Being iterable, we may loop over `text` and do something with the individual characters, for example, print them out with extra space in between them." ] }, { @@ -801,12 +799,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "W H U - O t t o B e i s h e i m S c h o o l o f M a n a g e m e n t " + "L o r e m i p s u m d o l o r s i t a m e t , c o n s e c t e t u r . . . " ] } ], "source": [ - "for letter in school:\n", + "for letter in text:\n", " print(letter, end=\" \")" ] }, @@ -818,7 +816,9 @@ } }, "source": [ - "Being a container, we can check if a given object is a member of a sequence with the `in` operator. In the context of `str` objects, the `in` operator has *two* usages: First, it checks if a *single* character is contained in a `str` object. Second, it may also check if a shorter `str` object, then called a **substring**, is contained in a longer one." + "Being a container, we may check if a given `str` object is contained in `text` with the `in` operator.\n", + "\n", + "The `in` operator has *two* usages: First, it checks if a *single* character is contained in a `str` object. Second, it may also check if a shorter `str` object, then called a **substring**, is contained in a longer one." ] }, { @@ -842,7 +842,7 @@ } ], "source": [ - "\"O\" in school" + "\"L\" in text" ] }, { @@ -866,7 +866,7 @@ } ], "source": [ - "\"WHU\" in school" + "\"ipsum\" in text" ] }, { @@ -890,7 +890,7 @@ } ], "source": [ - "\"EBS\" in school" + "\"veni, vidi, vici\" in text" ] }, { @@ -927,7 +927,7 @@ { "data": { "text/plain": [ - "'W'" + "'L'" ] }, "execution_count": 28, @@ -936,7 +936,7 @@ } ], "source": [ - "school[0]" + "text[0]" ] }, { @@ -951,7 +951,7 @@ { "data": { "text/plain": [ - "'H'" + "'o'" ] }, "execution_count": 29, @@ -960,7 +960,7 @@ } ], "source": [ - "school[1]" + "text[1]" ] }, { @@ -971,7 +971,7 @@ } }, "source": [ - "The index must be of type `int`." + "The index must be of type `int` or we get a `TypeError`." ] }, { @@ -979,7 +979,7 @@ "execution_count": 30, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -990,13 +990,13 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mschool\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1.0\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1.0\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: string indices must be integers" ] } ], "source": [ - "school[1.0]" + "text[1.0]" ] }, { @@ -1015,14 +1015,14 @@ "execution_count": 31, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ - "'t'" + "'.'" ] }, "execution_count": 31, @@ -1031,7 +1031,7 @@ } ], "source": [ - "school[39]" + "text[42] # = len(text) - 1" ] }, { @@ -1061,13 +1061,13 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mschool\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m40\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m43\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# = len(text)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: string index out of range" ] } ], "source": [ - "school[40]" + "text[43] # = len(text)" ] }, { @@ -1078,7 +1078,7 @@ } }, "source": [ - "We may use *negative* indexes to start counting from the end of the `str` object." + "We may use *negative* indexes to start counting from the end of the `str` object. That only works because sequences are *finite*." ] }, { @@ -1093,7 +1093,7 @@ { "data": { "text/plain": [ - "'t'" + "'.'" ] }, "execution_count": 33, @@ -1102,7 +1102,7 @@ } ], "source": [ - "school[-1]" + "text[-1]" ] }, { @@ -1128,7 +1128,7 @@ { "data": { "text/plain": [ - "'O'" + "'i'" ] }, "execution_count": 34, @@ -1137,7 +1137,7 @@ } ], "source": [ - "school[6]" + "text[6]" ] }, { @@ -1152,7 +1152,7 @@ { "data": { "text/plain": [ - "'O'" + "'i'" ] }, "execution_count": 35, @@ -1161,7 +1161,7 @@ } ], "source": [ - "school[-34]" + "text[-37]" ] }, { @@ -1185,7 +1185,9 @@ "source": [ "A **slice** is a substring of a `str` object.\n", "\n", - "The **slicing operator** is a generalization of the indexing operator: We can put one, two, or three integers within the brackets, separated by colons `:`. The three integers are then referred to as the *start*, *end*, and *step* values." + "The **slicing operator** is a generalization of the indexing operator: We can put one, two, or three integers within the brackets, separated by colons `:`. The three integers are then referred to as the *start*, *end*, and *step* values.\n", + "\n", + "Let's start with two integers, *start* and *end*." ] }, { @@ -1200,7 +1202,7 @@ { "data": { "text/plain": [ - "'WHU'" + "'Lorem'" ] }, "execution_count": 36, @@ -1209,7 +1211,7 @@ } ], "source": [ - "school[0:3]" + "text[0:5]" ] }, { @@ -1220,7 +1222,9 @@ } }, "source": [ - "Whereas the *start* is always included in the result, the *end* is not. Counter-intuitive at first, this makes working with individual slices easier as they add up to the original `str` object again. As the *end* is not included, we must end the second slice with `len(school)` or `40` below." + "Whereas the *start* is always included in the result, the *end* is not. Counter-intuitive at first, this makes working with individual slices easier as they add up to the original `str` object again.\n", + "\n", + "So, as the *end* is *not* included, we must end the second slice with `len(text)` or `43` below." ] }, { @@ -1235,7 +1239,7 @@ { "data": { "text/plain": [ - "'WHU - Otto Beisheim School of Management'" + "'Lorem ipsum dolor sit amet, consectetur ...'" ] }, "execution_count": 37, @@ -1244,7 +1248,7 @@ } ], "source": [ - "school[0:3] + school[3:40]" + "text[0:5] + text[5:len(text)]" ] }, { @@ -1255,7 +1259,7 @@ } }, "source": [ - "For convenience, the indexes do not need to lie in the range from 0 to the `str` object's \"length\" when slicing. This is *not* the case for indexing as the `IndexError` above shows." + "For convenience, the indexes do not need to lie within the range from `0` to `len(text)` when slicing." ] }, { @@ -1270,7 +1274,7 @@ { "data": { "text/plain": [ - "'WHU - Otto Beisheim School of Management'" + "'Lorem ipsum dolor sit amet, consectetur ...'" ] }, "execution_count": 38, @@ -1279,7 +1283,7 @@ } ], "source": [ - "school[0:999]" + "text[0:999]" ] }, { @@ -1305,7 +1309,7 @@ { "data": { "text/plain": [ - "'WHU - Otto Beisheim School of Management'" + "'Lorem ipsum dolor sit amet, consectetur ...'" ] }, "execution_count": 39, @@ -1314,7 +1318,7 @@ } ], "source": [ - "school[:3] + school[3:]" + "text[:5] + text[5:]" ] }, { @@ -1340,7 +1344,7 @@ { "data": { "text/plain": [ - "'WHU Otto Beisheim School'" + "'Lorem ipsum dolor sit amet.'" ] }, "execution_count": 40, @@ -1349,7 +1353,7 @@ } ], "source": [ - "school[:3] + school[5:26]" + "text[:26] + text[42]" ] }, { @@ -1375,7 +1379,7 @@ { "data": { "text/plain": [ - "'WU-Ot esemSho fMngmn'" + "'Lrmismdlrstae,cnettr..'" ] }, "execution_count": 41, @@ -1384,7 +1388,7 @@ } ], "source": [ - "school[::2]" + "text[::2]" ] }, { @@ -1410,7 +1414,7 @@ { "data": { "text/plain": [ - "'tnemeganaM fo loohcS miehsieB ottO - UHW'" + "'... rutetcesnoc ,tema tis rolod muspi meroL'" ] }, "execution_count": 42, @@ -1419,7 +1423,7 @@ } ], "source": [ - "school[::-1]" + "text[::-1]" ] }, { @@ -1443,9 +1447,9 @@ "source": [ "Whereas elements of a `list` object *may* be *re-assigned*, as shortly hinted at in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?), this is *not* allowed for `str` objects. Once created, they *cannot* be *changed*. Formally, we say that they are **immutable**. In that regard, `str` objects and all the numeric types in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb) are alike.\n", "\n", - "On the contrary, objects that may be changed after creation, are called **mutable**. We already saw in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?) how mutable objects are more difficult to reason about for a beginner, in particular, if more than *one* variable point to one. Yet, mutability does have its place in a programmer's toolbox, and we revisit this idea in the next chapters.\n", + "On the contrary, objects that may be changed after creation, are called **mutable**. We already saw in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?) how mutable objects are more difficult to reason about for a beginner, in particular, if more than *one* variable references it. Yet, mutability does have its place in a programmer's toolbox, and we revisit this idea in the next chapters.\n", "\n", - "`str` objects are *immutable* as the `TypeError` indicates: Assignment to an index is *not* supported by this type." + "The `TypeError` indicates that `str` objects are *immutable*: Assignment to an index or a slice are *not* supported." ] }, { @@ -1464,66 +1468,18 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mschool\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\"E\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\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\"Z\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" ] } ], "source": [ - "school[0] = \"E\"" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The only thing we can do is to create a *new* `str` object in memory." + "text[0] = \"Z\"" ] }, { "cell_type": "code", "execution_count": 44, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "new_school = \"EBS\" + school[3:]" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'EBS - Otto Beisheim School of Management'" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "new_school" - ] - }, - { - "cell_type": "code", - "execution_count": 46, "metadata": { "slideshow": { "slide_type": "-" @@ -1531,125 +1487,19 @@ }, "outputs": [ { - "data": { - "text/plain": [ - "140488987187120" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" + "ename": "TypeError", + "evalue": "'str' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtext\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"random\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" + ] } ], "source": [ - "id(new_school)" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "140488988107952" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "id(school)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "## String Operations" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As mentioned before, the `+` and `*` operators are *overloaded* and used for **string concatenation**." - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "greeting = \"Hello \"" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'Hello WHU'" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "greeting + school[:3]" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'WHU WHU WHU WHU WHU WHU WHU WHU WHU WHU '" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "10 * school[:4]" + "text[:5] = \"random\"" ] }, { @@ -1678,7 +1528,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 45, "metadata": { "slideshow": { "slide_type": "slide" @@ -1688,21 +1538,45 @@ { "data": { "text/plain": [ - "6" + "'Lorem ipsum dolor sit amet, consectetur ...'" ] }, - "execution_count": 51, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"O\")" + "text" ] }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 46, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "22" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "text.find(\"a\")" + ] + }, + { + "cell_type": "code", + "execution_count": 47, "metadata": { "slideshow": { "slide_type": "-" @@ -1715,18 +1589,18 @@ "-1" ] }, - "execution_count": 52, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"Z\")" + "text.find(\"z\")" ] }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 48, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1736,16 +1610,16 @@ { "data": { "text/plain": [ - "11" + "12" ] }, - "execution_count": 53, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"Beisheim\")" + "text.find(\"dolor\")" ] }, { @@ -1761,7 +1635,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 49, "metadata": { "slideshow": { "slide_type": "slide" @@ -1771,21 +1645,21 @@ { "data": { "text/plain": [ - "12" + "1" ] }, - "execution_count": 54, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"e\")" + "text.find(\"o\")" ] }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 50, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1795,24 +1669,24 @@ { "data": { "text/plain": [ - "16" + "13" ] }, - "execution_count": 55, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"e\", 13) # 13 not 12 as otherwise the same character is found" + "text.find(\"o\", 2) # 2 not 1 as otherwise the same \"o\" is found again" ] }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 51, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -1822,13 +1696,13 @@ "-1" ] }, - "execution_count": 56, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.find(\"e\", 13, 15) # \"e\" does not occur in the specified slice" + "text.find(\"o\", 2, 12) # \"o\" does not occur in the specified slice" ] }, { @@ -1844,7 +1718,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 52, "metadata": { "slideshow": { "slide_type": "slide" @@ -1854,16 +1728,16 @@ { "data": { "text/plain": [ - "4" + "1" ] }, - "execution_count": 57, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.count(\"o\")" + "text.count(\"l\")" ] }, { @@ -1874,12 +1748,12 @@ } }, "source": [ - "As [count()](https://docs.python.org/3/library/stdtypes.html#str.count) is *case-sensitive*, we must **chain** it with the [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower) method to get the count of all \"O\"s and \"o\"s." + "As [count()](https://docs.python.org/3/library/stdtypes.html#str.count) is *case-sensitive*, we must **chain** it with the [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower) method to get the count of all `\"L\"`s and `\"l\"`s." ] }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 53, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1889,16 +1763,16 @@ { "data": { "text/plain": [ - "5" + "2" ] }, - "execution_count": 58, + "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.lower().count(\"o\")" + "text.lower().count(\"l\")" ] }, { @@ -1909,12 +1783,12 @@ } }, "source": [ - "Alternatively, we may use the [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) method and search for \"O\"s." + "Alternatively, we may use the [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) method and search for `\"O\"`s." ] }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 54, "metadata": { "slideshow": { "slide_type": "skip" @@ -1924,16 +1798,16 @@ { "data": { "text/plain": [ - "5" + "2" ] }, - "execution_count": 59, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "school.upper().count(\"O\")" + "text.upper().count(\"L\")" ] }, { @@ -1944,12 +1818,12 @@ } }, "source": [ - "Because `str` objects are *immutable*, the methods always return *new* objects, even if a method does *not* change the value of the `str` object at all." + "Because `str` objects are *immutable*, [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) and [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower) return *new* `str` objects, even if they do *not* change the value of the original `str` object." ] }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 55, "metadata": { "slideshow": { "slide_type": "slide" @@ -1957,12 +1831,12 @@ }, "outputs": [], "source": [ - "example = \"test\"" + "example = \"random\"" ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 56, "metadata": { "slideshow": { "slide_type": "-" @@ -1972,10 +1846,10 @@ { "data": { "text/plain": [ - "140489068668384" + "139674947440512" ] }, - "execution_count": 61, + "execution_count": 56, "metadata": {}, "output_type": "execute_result" } @@ -1986,7 +1860,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 57, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1999,7 +1873,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "-" @@ -2009,10 +1883,10 @@ { "data": { "text/plain": [ - "140488987340848" + "139674887826488" ] }, - "execution_count": 63, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -2034,7 +1908,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 59, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2047,7 +1921,7 @@ "False" ] }, - "execution_count": 64, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -2058,7 +1932,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 60, "metadata": { "slideshow": { "slide_type": "-" @@ -2071,7 +1945,7 @@ "True" ] }, - "execution_count": 65, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } @@ -2088,12 +1962,14 @@ } }, "source": [ - "Another popular string method is [split()](https://docs.python.org/3/library/stdtypes.html#str.split): It separates a longer `str` object into a list of smaller ones. By default, groups of whitespace are used as the *separator*." + "Another popular string method is [split()](https://docs.python.org/3/library/stdtypes.html#str.split): It separates a longer `str` object into smaller ones contained in a `list` object. By default, groups of contiguous whitespace are used as the *separator*.\n", + "\n", + "As an example, we use [split()](https://docs.python.org/3/library/stdtypes.html#str.split) to print out the individual words in `text` on separate lines." ] }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "slide" @@ -2104,18 +1980,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "WHU\n", - "-\n", - "Otto\n", - "Beisheim\n", - "School\n", - "of\n", - "Management\n" + "Lorem\n", + "ipsum\n", + "dolor\n", + "sit\n", + "amet,\n", + "consectetur\n", + "...\n" ] } ], "source": [ - "for word in school.split():\n", + "for word in text.split():\n", " print(word)" ] }, @@ -2132,7 +2008,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "slide" @@ -2145,7 +2021,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "-" @@ -2158,7 +2034,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "-" @@ -2171,7 +2047,7 @@ "'This will become a sentence'" ] }, - "execution_count": 69, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -2193,7 +2069,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2206,7 +2082,7 @@ "'a b c d e'" ] }, - "execution_count": 70, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -2223,12 +2099,12 @@ } }, "source": [ - "The [replace()](https://docs.python.org/3/library/stdtypes.html#str.replace) method creates a *new* `str` object with parts of the text replaced." + "The [replace()](https://docs.python.org/3/library/stdtypes.html#str.replace) method creates a *new* `str` object with parts of the original `str` object potentially replaced." ] }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 66, "metadata": { "slideshow": { "slide_type": "slide" @@ -2241,7 +2117,7 @@ "'This is a sentence'" ] }, - "execution_count": 71, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -2258,7 +2134,7 @@ } }, "source": [ - "## String Comparison" + "## String Operations" ] }, { @@ -2269,12 +2145,82 @@ } }, "source": [ - "The *relational* operators also work with `str` objects, another example of operator overloading. Comparison is done one character at a time until the first pair differs or one operand ends. However, `str` objects are sorted in a \"weird\" way. The reason for this is that computers store characters internally as numbers (i.e., $0$s and $1$s). Depending on the character encoding, these numbers vary. Commonly, characters and symbols used in the American language are encoded with the numbers 0 through 127, the so-called [ASCII standard](https://en.wikipedia.org/wiki/ASCII). However, Python works with the more general [Unicode/UTF-8 standard](https://en.wikipedia.org/wiki/UTF-8) that understands every language ever used by humans, even emojis." + "As mentioned in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Operator-Overloading), the `+` and `*` operators are *overloaded* and used for **string concatenation**. They always create *new* `str` objects. That has nothing to do with the `str` type's immutability, but is the default behavior of operators." ] }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 67, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello Lore'" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"Hello \" + text[:4]" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum '" + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "5 * text[:12]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### String Comparison" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The *relational* operators also work with `str` objects, another example of operator overloading. Comparison is done one character at a time until the first pair differs or one operand ends. However, `str` objects are sorted in a \"weird\" way. The reason for this is that computers store characters internally as numbers (i.e., $0$s and $1$s). Depending on the character encoding, these numbers vary. Commonly, characters and symbols used in American English are encoded with the numbers 0 through 127, the so-called [ASCII standard](https://en.wikipedia.org/wiki/ASCII). However, Python works with the more general [Unicode/UTF-8 standard](https://en.wikipedia.org/wiki/UTF-8) that understands every language ever used by humans, even emojis." + ] + }, + { + "cell_type": "code", + "execution_count": 69, "metadata": { "slideshow": { "slide_type": "slide" @@ -2289,7 +2235,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 70, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2302,7 +2248,7 @@ "True" ] }, - "execution_count": 73, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -2313,7 +2259,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "-" @@ -2326,7 +2272,7 @@ "False" ] }, - "execution_count": 74, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -2348,7 +2294,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 72, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2361,7 +2307,7 @@ "True" ] }, - "execution_count": 75, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } @@ -2378,12 +2324,12 @@ } }, "source": [ - "To provide a simple intuition for the \"weird\" sorting above, let's think of the American alphabet as being represented by the numbers as listed below. Then `\"Banana\"` is clearly \"smaller\" than `\"apple\"`." + "To provide a simple intuition for the \"weird\" sorting above, let's think of the alphabet as being represented by the numbers as listed below. Then `\"Banana\"` is clearly \"smaller\" than `\"apple\"`. In general, all the upper case letters are \"smaller\" than all the lower case letters." ] }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 73, "metadata": { "slideshow": { "slide_type": "slide" @@ -2479,7 +2425,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "slide" @@ -2493,7 +2439,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "-" @@ -2506,7 +2452,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 78, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -2528,7 +2474,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "slide" @@ -2541,7 +2487,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": 77, "metadata": { "slideshow": { "slide_type": "-" @@ -2554,7 +2500,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 80, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -2565,7 +2511,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "-" @@ -2578,7 +2524,7 @@ "'Pi is 3.142'" ] }, - "execution_count": 81, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -2611,7 +2557,7 @@ }, { "cell_type": "code", - "execution_count": 82, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "slide" @@ -2624,7 +2570,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 82, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -2646,7 +2592,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2659,7 +2605,7 @@ "'Good morning, Alexander'" ] }, - "execution_count": 83, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -2681,7 +2627,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2694,7 +2640,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 84, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -2716,7 +2662,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2729,7 +2675,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 85, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2764,7 +2710,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "skip" @@ -2777,7 +2723,7 @@ "'Pi is 3.14'" ] }, - "execution_count": 86, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -2799,7 +2745,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "skip" @@ -2812,7 +2758,7 @@ "'Hello Alexander! Good morning.'" ] }, - "execution_count": 87, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -2847,7 +2793,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 85, "metadata": { "slideshow": { "slide_type": "slide" @@ -2870,7 +2816,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 86, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2902,7 +2848,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 87, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2934,7 +2880,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 88, "metadata": { "slideshow": { "slide_type": "skip" @@ -2947,7 +2893,7 @@ "'This is a sentence\\nthat is printed\\non three lines.'" ] }, - "execution_count": 91, + "execution_count": 88, "metadata": {}, "output_type": "execute_result" } @@ -2982,7 +2928,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 89, "metadata": { "slideshow": { "slide_type": "slide" @@ -3015,7 +2961,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 90, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3024,10 +2970,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "(unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape (, line 1)", + "evalue": "(unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(\"C:\\Users\\Administrator\\Desktop\\Project_Folder\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(\"C:\\Users\\Administrator\\Desktop\\Project_Folder\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \\UXXXXXXXX escape\n" ] } ], @@ -3048,7 +2994,7 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 91, "metadata": { "slideshow": { "slide_type": "slide" @@ -3069,7 +3015,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 92, "metadata": { "slideshow": { "slide_type": "-" @@ -3101,7 +3047,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 93, "metadata": { "slideshow": { "slide_type": "slide" @@ -3122,7 +3068,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 94, "metadata": { "slideshow": { "slide_type": "-" @@ -3165,7 +3111,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 95, "metadata": { "slideshow": { "slide_type": "slide" @@ -3174,10 +3120,10 @@ "outputs": [ { "ename": "SyntaxError", - "evalue": "EOL while scanning string literal (, line 1)", + "evalue": "EOL while scanning string literal (, line 1)", "output_type": "error", "traceback": [ - "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m EOL while scanning string literal\n" + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m \"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m EOL while scanning string literal\n" ] } ], @@ -3200,7 +3146,7 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 96, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3227,7 +3173,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 97, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3240,7 +3186,7 @@ "'\\nI am a multi-line string\\nconsisting of 4 lines.\\n'" ] }, - "execution_count": 100, + "execution_count": 97, "metadata": {}, "output_type": "execute_result" } @@ -3262,7 +3208,7 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 98, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3297,7 +3243,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 99, "metadata": { "slideshow": { "slide_type": "slide" @@ -3333,7 +3279,7 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "slide" @@ -3347,7 +3293,7 @@ }, { "cell_type": "code", - "execution_count": 104, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "-" @@ -3360,7 +3306,7 @@ "\"Lorem Ipsum is simply dummy text of the printing and typesetting industry.\\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s\\nwhen an unknown printer took a galley of type and scrambled it to make a type\\nspecimen book. It has survived not only five centuries but also the leap into\\nelectronic typesetting, remaining essentially unchanged. It was popularised in\\nthe 1960s with the release of Letraset sheets.\\n\"" ] }, - "execution_count": 104, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -3371,7 +3317,7 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "-" diff --git a/07_sequences.ipynb b/07_sequences.ipynb index 11add0a..f20b670 100644 --- a/07_sequences.ipynb +++ b/07_sequences.ipynb @@ -23,7 +23,7 @@ "\n", "The `str` type is a bit of a corner case in this regard. While one could argue that a longer `str` object, for example, `\"text\"`, is composed of individual characters, this is *not* the case in memory as the literal `\"text\"` only creates *one* object (i.e., one \"bag\" of $0$s and $1$s modeling all characters).\n", "\n", - "This chapter and Chapter 8 introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", + "This chapter and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings.ipynb) introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", "\n", "In this chapter, we focus on data types that model all kinds of sequential data. Examples of such data are [spreadsheets](https://en.wikipedia.org/wiki/Spreadsheet) or [matrices](https://en.wikipedia.org/wiki/Matrix_%28mathematics%29)/[vectors](https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29). Such formats share the property that they are composed of smaller units that come in a sequence of, for example, rows/columns/cells or elements/entries." ] @@ -49,9 +49,9 @@ "source": [ "[Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb#A-\"String\"-of-Characters) already describes the *sequence* properties of `str` objects. Here, we take a step back and study these properties on their own before looking at bigger ideas.\n", "\n", - "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter according to their behavior in various contexts.\n", + "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings.ipynb) according to their behavior in various contexts.\n", "\n", - "As an illustration, consider `numbers` and `word` below, two objects of *different* types." + "As an illustration, consider `numbers` and `text` below, two objects of *different* types." ] }, { @@ -65,7 +65,7 @@ "outputs": [], "source": [ "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]\n", - "word = \"random\"" + "text = \"Lorem ipsum dolor sit amet, consectetur ...\"" ] }, { @@ -76,7 +76,7 @@ } }, "source": [ - "They have in common that we may loop over them with the `for` statement. So, in the context of iteration, both exhibit the *same* behavior." + "Among others, one commonality between the two is that we may loop over them with the `for` statement. So, in the context of iteration, both exhibit the *same* behavior." ] }, { @@ -114,12 +114,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "r a n d o m " + "L o r e m i p s u m d o l o r s i t a m e t , c o n s e c t e t u r . . . " ] } ], "source": [ - "for character in word:\n", + "for character in text:\n", " print(character, end=\" \")" ] }, @@ -133,7 +133,7 @@ "source": [ "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables), we referred to such types as *iterables*. That is *not* a proper [English](https://dictionary.cambridge.org/spellcheck/english-german/?q=iterable) word, even if it may sound like one at first sight. Yet, it is an official term in the Python world formalized with the `Iterable` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module.\n", "\n", - "For the data science practitioner, it is worthwhile to know such terms as, for example, the documentation on the [built-ins](https://docs.python.org/3/library/functions.html) uses them extensively: In simple words, any built-in that takes an argument called \"*iterable*\" may be called with *any* object that supports being looped over. Already familiar [built-ins](https://docs.python.org/3/library/functions.html) include, among others, [enumerate()](https://docs.python.org/3/library/functions.html#enumerate), [sum()](https://docs.python.org/3/library/functions.html#sum), or [zip()](https://docs.python.org/3/library/functions.html#zip). So, they do *not* require the argument to be of a certain concrete data type (e.g., `list`); instead, any *iterable* type works." + "For the data science practitioner, it is worthwhile to know such terms as, for example, the documentation on the [built-ins](https://docs.python.org/3/library/functions.html) uses them extensively: In simple words, any built-in that takes an argument called \"*iterable*\" may be called with *any* object that supports being looped over. Already familiar [built-ins](https://docs.python.org/3/library/functions.html) include [enumerate()](https://docs.python.org/3/library/functions.html#enumerate), [sum()](https://docs.python.org/3/library/functions.html#sum), or [zip()](https://docs.python.org/3/library/functions.html#zip). So, they do *not* require the argument to be of a certain data type (e.g., `list`); instead, any *iterable* type works." ] }, { @@ -183,7 +183,7 @@ "source": [ "As in the context of *goose typing* in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check if an object supports a behavior.\n", "\n", - "So, let's \"ask\" Python if it can loop over `numbers` or `word`." + "So, let's \"ask\" Python if it can loop over `numbers` or `text`." ] }, { @@ -231,7 +231,7 @@ } ], "source": [ - "isinstance(word, abc.Iterable)" + "isinstance(text, abc.Iterable)" ] }, { @@ -315,7 +315,7 @@ }, "source": [ "Most of the data types in this and the next chapter exhibit three [orthogonal](https://en.wikipedia.org/wiki/Orthogonality) (i.e., \"independent\") behaviors, formalized by ABCs in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module as:\n", - "- `Iterable`: An object supports being looped over.\n", + "- `Iterable`: An object may be looped over.\n", "- `Container`: An object \"contains\" references to other objects; a \"whole\" is composed of many \"parts.\"\n", "- `Sized`: The number of references to other objects, the \"parts,\" is *finite*.\n", "\n", @@ -367,7 +367,7 @@ } ], "source": [ - "\"r\" in word" + "\"l\" in text" ] }, { @@ -378,7 +378,7 @@ } }, "source": [ - "Alternatively, we could also check if `numbers` and `word` are `Container` types with the [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function." + "Alternatively, we could also check if `numbers` and `text` are `Container` types with [isinstance()](https://docs.python.org/3/library/functions.html#isinstance)." ] }, { @@ -426,7 +426,7 @@ } ], "source": [ - "isinstance(word, abc.Container)" + "isinstance(text, abc.Container)" ] }, { @@ -497,7 +497,7 @@ } }, "source": [ - "Analogously, being `Sized` types, we can pass `numbers` and `word` as the argument to the built-in [len()](https://docs.python.org/3/library/functions.html#len) function and obtain \"meaningful\" results. The exact meaning depends on the *concrete* data type: For `numbers`, [len()](https://docs.python.org/3/library/functions.html#len) tells us how many elements are in the `list` object; for `word`, it tells us how many [Unicode characters](https://en.wikipedia.org/wiki/Unicode) make up the `str` object. But, *abstractly* speaking, both data types exhibit the *same* behavior of *finiteness*." + "Analogously, being `Sized` types, we can pass `numbers` and `text` as the argument to the built-in [len()](https://docs.python.org/3/library/functions.html#len) function and obtain \"meaningful\" results. The exact meaning depends on the data type: For `numbers`, [len()](https://docs.python.org/3/library/functions.html#len) tells us how many elements are in the `list` object; for `text`, it tells us how many [Unicode characters](https://en.wikipedia.org/wiki/Unicode) make up the `str` object. *Abstractly* speaking, both data types exhibit the *same* behavior of *finiteness*." ] }, { @@ -536,7 +536,7 @@ { "data": { "text/plain": [ - "6" + "43" ] }, "execution_count": 17, @@ -545,7 +545,7 @@ } ], "source": [ - "len(word)" + "len(text)" ] }, { @@ -593,7 +593,7 @@ } ], "source": [ - "isinstance(word, abc.Sized)" + "isinstance(text, abc.Sized)" ] }, { @@ -666,7 +666,9 @@ "source": [ "These three behaviors are so essential that whenever they coincide for a data type, it is called a **collection**, formalized with the `Collection` ABC. That is where the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module got its name from: It summarizes all ABCs related to collections; in particular, it defines a hierarchy of specialized kinds of collections.\n", "\n", - "So, both `numbers` and `word` are collections." + "Without going into too much detail, one way to read the summary table at the beginning of the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module's documention is as follows: The first column, titled \"ABC\", lists all collection-related ABCs in Python. The second column, titled \"Inherits from,\" indicates if the idea behind the ABC is *original* (e.g., the first row with the `Container` ABC has an empty \"Inherits from\" column) or a *combination* (e.g., the row with the `Collection` ABC has `Sized`, `Iterable`, and `Container` in the \"Inherits from\" column). The third and fourth columns list the methods that come with a data type following an ABC. We keep ignoring the methods named in the dunder style for now.\n", + "\n", + "So, let's confirm that both `numbers` and `text` are collections." ] }, { @@ -714,7 +716,7 @@ } ], "source": [ - "isinstance(word, abc.Collection)" + "isinstance(text, abc.Collection)" ] }, { @@ -727,7 +729,7 @@ "source": [ "They share one more common behavior: When looping over them, we can *predict* the *order* of the elements or characters. The ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module corresponding to this behavior is `Reversible`. While sounding unintuitive at first, it is evident that if something is reversible, it must have a forward order, to begin with.\n", "\n", - "We add the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in to the `for`-loop from above to iterate over the elements or characters in reverse order." + "The [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in allows us to loop over the elements or characters in reverse order." ] }, { @@ -765,12 +767,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "m o d n a r " + ". . . r u t e t c e s n o c , t e m a t i s r o l o d m u s p i m e r o L " ] } ], "source": [ - "for character in reversed(word):\n", + "for character in reversed(text):\n", " print(character, end=\" \")" ] }, @@ -819,7 +821,7 @@ } ], "source": [ - "isinstance(word, abc.Reversible)" + "isinstance(text, abc.Reversible)" ] }, { @@ -878,7 +880,7 @@ } ], "source": [ - "isinstance(word, abc.Sequence)" + "isinstance(text, abc.Sequence)" ] }, { @@ -976,7 +978,7 @@ } }, "source": [ - "[PythonTutor](http://www.pythontutor.com/visualize.html#code=empty%20%3D%20%5B%5D%0Asimple%20%3D%20%5B40,%2050%5D%0Anested%20%3D%20%5Bempty,%2010,%2020.0,%20%22Thirty%22,%20simple%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how `nested` holds references to the `empty` and `simple` objects. Technically, it holds three more references pointing to the `10`, `20.0`, and `\"Thirty\"` objects as well. However, to simplify the visualization, these three objects are shown right inside the `nested` object as they are immutable and of \"flat\" data types. In general, the $0$s and $1$s inside a `list` object in memory always constitute pointers to other objects only." + "[PythonTutor](http://www.pythontutor.com/visualize.html#code=empty%20%3D%20%5B%5D%0Asimple%20%3D%20%5B40,%2050%5D%0Anested%20%3D%20%5Bempty,%2010,%2020.0,%20%22Thirty%22,%20simple%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how `nested` holds references to the `empty` and `simple` objects. Technically, it holds three more references to the `10`, `20.0`, and `\"Thirty\"` objects as well. However, to simplify the visualization, these three objects are shown right inside the `nested` object. That may be done because they are immutable and \"flat\" data types. In general, the $0$s and $1$s inside a `list` object in memory always constitute references to other objects only." ] }, { @@ -1026,7 +1028,7 @@ { "data": { "text/plain": [ - "140322034424136" + "140157873498184" ] }, "execution_count": 34, @@ -1070,7 +1072,7 @@ } }, "source": [ - "Alternatively, we may use the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in to create a `list` object out of an iterable we pass to it as the argument.\n", + "Alternatively, we use the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in to create a `list` object out of an iterable we pass to it as the argument.\n", "\n", "For example, we can wrap the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in with [list()](https://docs.python.org/3/library/functions.html#func-list): As described in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb#Containers-vs.-Iterables), `range` objects, like `range(1, 13)` below, are iterable and generate `int` objects \"on the fly\" (i.e., one by one). The [list()](https://docs.python.org/3/library/functions.html#func-list) around it acts like a `for`-loop and **materializes** twelve `int` objects in memory that then become the elements of the newly created `list` object. [PythonTutor](http://www.pythontutor.com/visualize.html#code=r%20%3D%20range%281,%2013%29%0Al%20%3D%20list%28range%281,%2013%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows this difference visually." ] @@ -1167,7 +1169,7 @@ } }, "source": [ - "As another example, we may also create a `list` object from a `str` object as the latter is iterable, as well. Then, the individual characters become the elements of the new `list` object!" + "As another example, we create a `list` object from a `str` object, which is iterable, as well. Then, the individual characters become the elements of the new `list` object!" ] }, { @@ -1182,7 +1184,7 @@ { "data": { "text/plain": [ - "['W', 'H', 'U']" + "['i', 't', 'e', 'r', 'a', 'b', 'l', 'e']" ] }, "execution_count": 39, @@ -1191,7 +1193,7 @@ } ], "source": [ - "list(\"WHU\")" + "list(\"iterable\")" ] }, { @@ -1213,7 +1215,7 @@ } }, "source": [ - "`list` objects are *sequences*. To reiterate that concept from above *without* the formal ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module, we briefly summarize the *four* behaviors of a sequence and provide some more `list`-specific details below:" + "`list` objects are *sequences*. To reiterate that, we briefly summarize the *four* behaviors of a sequence and provide some more `list`-specific details below:" ] }, { @@ -1224,16 +1226,16 @@ } }, "source": [ - "- **Container**:\n", + "- `Container`:\n", " - holds references to other objects in memory (with their own *identity* and *type*)\n", " - implements membership testing via the `in` operator\n", - "- **Iterable**:\n", + "- `Iterable`:\n", " - supports being looped over\n", " - works with the `for` or `while` statements\n", - "- **Reversible**:\n", + "- `Reversible`:\n", " - the elements come in a *predictable* order that we may traverse in a forward or backward fashion\n", " - works with the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in\n", - "- **Sized**:\n", + "- `Sized`:\n", " - the number of elements is finite *and* known in advance\n", " - works with the built-in [len()](https://docs.python.org/3/library/functions.html#len) function" ] @@ -1246,7 +1248,7 @@ } }, "source": [ - "The \"length\" of `nested` is *five* because `simple` counts as only *one* element. In other words, `nested` holds five references to other objects." + "The \"length\" of `nested` is *five* because `empty` and `simple` count as *one* element each. In other words, `nested` holds five references to other objects, two of which are `list` objects." ] }, { @@ -1281,7 +1283,7 @@ } }, "source": [ - "With a `for`-loop, we can traverse all elements in a *predictable* order, forward or backward. As `list` objects only hold references to other objects, these have a *indentity* and may be of *different* types; however, this is rarely, if ever, useful in practice." + "With a `for`-loop, we can iterate over all elements in a *predictable* order, forward or backward. As `list` objects hold *references* to other *objects*, these have an *indentity* and may even be of *different* types; however, the latter observation is rarely, if ever, useful in practice." ] }, { @@ -1297,11 +1299,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "[] \t140322025703432 \t\n", - "10 \t94360180081984 \t\n", - "20.0 \t140322034534104 \t\n", - "Thirty \t140322025251816 \t\n", - "[40, 50] \t140322034424072 \t\n" + "[] \t140157882223304 \t\n", + "10 \t93987402609984 \t\n", + "20.0 \t140157882328912 \t\n", + "Thirty \t140157873509520 \t\n", + "[40, 50] \t140157873031176 \t\n" ] } ], @@ -1340,7 +1342,7 @@ } }, "source": [ - "The `in` operator checks if a given object is \"contained\" in a `list` object. It uses the `==` operator behind the scenes (i.e., *not* the `is` operator) conducting a so-called **[linear search](https://en.wikipedia.org/wiki/Linear_search)**: So, Python implicitly loops over *all* elements and only stops prematurely if an element evaluates equal to the given object. A linear search may, therefore, be relatively *slow* for big `list` objects." + "The `in` operator checks if a given object is \"contained\" in a `list` object. It uses the `==` operator behind the scenes (i.e., *not* the `is` operator) conducting a **[linear search](https://en.wikipedia.org/wiki/Linear_search)**: So, Python implicitly loops over *all* elements and only stops prematurely if an element evaluates equal to the searched object. A linear search may, therefore, be relatively *slow* for big `list` objects." ] }, { @@ -1445,9 +1447,9 @@ } }, "source": [ - "Because of the *predictable* order and the *finiteness*, each element in a sequence can be labeled with a unique *index* (i.e., an `int` object in the range $0 \\leq \\text{index} < \\lvert \\text{sequence} \\rvert$).\n", + "Because of the *predictable* order and the *finiteness*, each element in a sequence can be labeled with a unique *index*, an `int` object in the range $0 \\leq \\text{index} < \\lvert \\text{sequence} \\rvert$.\n", "\n", - "Brackets, `[` and `]`, are the literal syntax for accessing individual elements of any sequence type. In this book, we also call them the *indexing operator*." + "Brackets, `[` and `]`, are the literal syntax for accessing individual elements of any sequence type. In this book, we also call them the *indexing operator* in this context." ] }, { @@ -1482,7 +1484,7 @@ } }, "source": [ - "The last index is one less than `len(nested)` above, and Python raises an `IndexError` if we look up an index that is not in the implied range." + "The last index is one less than `len(nested)`, and Python raises an `IndexError` if we look up an index that is not in the range." ] }, { @@ -1533,7 +1535,7 @@ { "data": { "text/plain": [ - "50" + "[40, 50]" ] }, "execution_count": 48, @@ -1541,6 +1543,30 @@ "output_type": "execute_result" } ], + "source": [ + "nested[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "50" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "nested[-1][1]" ] @@ -1571,7 +1597,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 50, "metadata": { "slideshow": { "slide_type": "slide" @@ -1584,7 +1610,7 @@ "[10, 20.0, 'Thirty']" ] }, - "execution_count": 49, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1601,12 +1627,12 @@ } }, "source": [ - "To obtain \"every other\" element, we slice from beginning to end, defaulting to `0` and `len(nested)`, in steps of `2`." + "To obtain \"every other\" element, we slice from beginning to end, defaulting to `0` and `len(nested)` when omitted, in steps of `2`." ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "metadata": { "slideshow": { "slide_type": "-" @@ -1619,7 +1645,7 @@ "[[], 20.0, [40, 50]]" ] }, - "execution_count": 50, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -1636,20 +1662,9 @@ } }, "source": [ - "The literal notation with the colons `:` is *syntactic sugar*, and Python provides the [slice()](https://docs.python.org/3/library/functions.html#slice) built-in to slice with `slice` objects. [slice()](https://docs.python.org/3/library/functions.html#slice) takes *start*, *stop*, and *step* arguments in the same way as the already familiar [range()](https://docs.python.org/3/library/functions.html#func-range) built-in." - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "middle = slice(1, 4)" + "The literal notation with the colons `:` is *syntactic sugar*. It saves us from using the [slice()](https://docs.python.org/3/library/functions.html#slice) built-in to create `slice` objects. [slice()](https://docs.python.org/3/library/functions.html#slice) takes *start*, *stop*, and *step* arguments in the same way as the familiar [range()](https://docs.python.org/3/library/functions.html#func-range), and the `slice` objects it creates are used just as *indexes* above.\n", + "\n", + "In most cases, the literal notation is more convenient to use; however, with `slice` objects, we can give names to slices and reuse them across several sequences." ] }, { @@ -1660,31 +1675,9 @@ "slide_type": "skip" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "slice" - ] - }, - "execution_count": 52, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "type(middle)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "In most cases, the literal notation is more convenient to use; however, with `slice` objects, we may give names to slices and re-use them across several sequences." + "middle = slice(1, 4)" ] }, { @@ -1699,7 +1692,7 @@ { "data": { "text/plain": [ - "[10, 20.0, 'Thirty']" + "slice" ] }, "execution_count": 53, @@ -1708,7 +1701,7 @@ } ], "source": [ - "nested[middle]" + "type(middle)" ] }, { @@ -1723,7 +1716,7 @@ { "data": { "text/plain": [ - "[11, 8, 5]" + "[10, 20.0, 'Thirty']" ] }, "execution_count": 54, @@ -1732,7 +1725,7 @@ } ], "source": [ - "numbers[middle]" + "nested[middle]" ] }, { @@ -1747,7 +1740,7 @@ { "data": { "text/plain": [ - "'and'" + "[11, 8, 5]" ] }, "execution_count": 55, @@ -1756,7 +1749,31 @@ } ], "source": [ - "word[middle]" + "numbers[middle]" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'ore'" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "text[middle]" ] }, { @@ -1772,7 +1789,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 57, "metadata": { "slideshow": { "slide_type": "skip" @@ -1785,7 +1802,7 @@ "1" ] }, - "execution_count": 56, + "execution_count": 57, "metadata": {}, "output_type": "execute_result" } @@ -1796,7 +1813,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 58, "metadata": { "slideshow": { "slide_type": "skip" @@ -1809,7 +1826,7 @@ "4" ] }, - "execution_count": 57, + "execution_count": 58, "metadata": {}, "output_type": "execute_result" } @@ -1831,7 +1848,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 59, "metadata": { "slideshow": { "slide_type": "skip" @@ -1855,7 +1872,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 60, "metadata": { "slideshow": { "slide_type": "slide" @@ -1868,7 +1885,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 61, "metadata": { "slideshow": { "slide_type": "-" @@ -1881,7 +1898,7 @@ "[[], 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 60, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } @@ -1898,14 +1915,14 @@ } }, "source": [ - "At first glance, `nested` and `nested_copy` seem to cause no pain. For `list` objects, the comparison operator `==` goes over the elements in both operands in a pairwise fashion and checks if they all evaluate equal.\n", + "At first glance, `nested` and `nested_copy` seem to cause no pain. For `list` objects, the comparison operator `==` goes over the elements in both operands in a pairwise fashion and checks if they all evaluate equal (cf., the \"*List Comparison*\" section below for more details).\n", "\n", - "We confirm that `nested` and `nested_copy` compare equal as expected but also that they are *different* objects." + "We confirm that `nested` and `nested_copy` compare equal as could be expected but also that they are *different* objects." ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 62, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1918,7 +1935,7 @@ "True" ] }, - "execution_count": 61, + "execution_count": 62, "metadata": {}, "output_type": "execute_result" } @@ -1929,7 +1946,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 63, "metadata": { "slideshow": { "slide_type": "-" @@ -1942,7 +1959,7 @@ "False" ] }, - "execution_count": 62, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } @@ -1959,14 +1976,14 @@ } }, "source": [ - "However, as [PythonTutor](http://pythontutor.com/visualize.html#code=nested%20%3D%20%5B%5B%5D,%2010,%2020.0,%20%22Thirty%22,%20%5B40,%2050%5D%5D%0Anested_copy%20%3D%20nested%5B%3A%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) reveals, only the *pointers* to the elements are copied! That concept is called a **[shallow copy](https://en.wikipedia.org/wiki/Object_copying#Shallow_copy)**.\n", + "However, as [PythonTutor](http://pythontutor.com/visualize.html#code=nested%20%3D%20%5B%5B%5D,%2010,%2020.0,%20%22Thirty%22,%20%5B40,%2050%5D%5D%0Anested_copy%20%3D%20nested%5B%3A%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) reveals, only the *references* to the elements are copied, and not the objects in `nested` themselves! Because of that, `nested_copy` is a so-called **[shallow copy](https://en.wikipedia.org/wiki/Object_copying#Shallow_copy)** of `nested`.\n", "\n", - "We could also see this with the [id()](https://docs.python.org/3/library/functions.html#id) function: The respective first elements in both `nested` and `nested_copy` are the *same* `empty` object." + "We could also see this with the [id()](https://docs.python.org/3/library/functions.html#id) function: The respective first elements in both `nested` and `nested_copy` are the *same* object, namely `empty`. So, we have three ways of accessing the *same* address in memory. Also, we say that `nested` and `nested_copy` partially share the *same* state." ] }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 64, "metadata": { "slideshow": { "slide_type": "fragment" @@ -1979,7 +1996,7 @@ "True" ] }, - "execution_count": 63, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -1990,7 +2007,7 @@ }, { "cell_type": "code", - "execution_count": 64, + "execution_count": 65, "metadata": { "slideshow": { "slide_type": "skip" @@ -2000,44 +2017,16 @@ { "data": { "text/plain": [ - "[]" + "140157882223304" ] }, - "execution_count": 64, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "nested[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Knowing this becomes critical if the elements in a `list` object are mutable objects. Then, because of the original `list` object and its copy both pointing at the *same* objects in memory, if some of them are mutated, these changes are visible to both! We already saw a similar kind of confusion in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb#Who-am-I?-And-how-many?) in a \"simpler\" setting and look into this in detail in the next section.\n", - "\n", - "Instead of a shallow copy, we could also create a so-called **[deep copy](https://en.wikipedia.org/wiki/Object_copying#Deep_copy)** of `nested`: That concept recursively follows every pointer in a possible nested data structure and creates copies of *every* involved object.\n", - "\n", - "To explicitly create shallow or deep copies, the [copy](https://docs.python.org/3/library/copy.html) module in the [standard library](https://docs.python.org/3/library/index.html) provides two functions, [copy()](https://docs.python.org/3/library/copy.html#copy.copy) and [deepcopy()](https://docs.python.org/3/library/copy.html#copy.deepcopy). We must always remember that slicing creates *shallow* copies only." - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [], - "source": [ - "import copy" + "id(nested[0])" ] }, { @@ -2048,9 +2037,20 @@ "slide_type": "skip" } }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "140157882223304" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "nested_deep_copy = copy.deepcopy(nested)" + "id(nested_copy[0])" ] }, { @@ -2065,7 +2065,7 @@ { "data": { "text/plain": [ - "True" + "140157882223304" ] }, "execution_count": 67, @@ -2073,6 +2073,73 @@ "output_type": "execute_result" } ], + "source": [ + "id(empty)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Knowing this becomes critical if the elements in a `list` object are mutable objects (i.e., we can change them *in place*), and this is the case with `nested` and `nested_copy`, as we see in the next section on \"*Mutability*\".\n", + "\n", + "As both the original `nested` object and its copy reference the *same* `list` objects in memory, any changes made to them are visible to both! Because of that, working with shallow copies can easily become confusing.\n", + "\n", + "Instead of a shallow copy, we could also create a so-called **[deep copy](https://en.wikipedia.org/wiki/Object_copying#Deep_copy)** of `nested`: Then, the copying process recursively follows every reference in a nested data structure and creates copies of *every* object found.\n", + "\n", + "To explicitly create shallow or deep copies, the [copy](https://docs.python.org/3/library/copy.html) module in the [standard library](https://docs.python.org/3/library/index.html) provides two functions, [copy()](https://docs.python.org/3/library/copy.html#copy.copy) and [deepcopy()](https://docs.python.org/3/library/copy.html#copy.deepcopy). We must always remember that slicing creates *shallow* copies only." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import copy" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "nested_deep_copy = copy.deepcopy(nested)" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "nested == nested_deep_copy" ] @@ -2090,7 +2157,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 71, "metadata": { "slideshow": { "slide_type": "skip" @@ -2103,7 +2170,7 @@ "False" ] }, - "execution_count": 68, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -2112,6 +2179,54 @@ "nested[0] is nested_deep_copy[0]" ] }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "140157882223304" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(nested[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "140157873029448" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(nested_deep_copy[0])" + ] + }, { "cell_type": "markdown", "metadata": { @@ -2142,12 +2257,12 @@ } }, "source": [ - "In contrast to `str` objects, `list` objects are *mutable*: We may assign new elements to indices or slices and also remove elements. That changes *parts* of a `list` object in memory." + "In contrast to `str` objects, `list` objects are *mutable*: We may assign new elements to indices or slices and also remove elements. That changes the *references* in a `list` object. In general, if an object is *mutable*, we say that it may be changed *in place*." ] }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 74, "metadata": { "slideshow": { "slide_type": "slide" @@ -2160,7 +2275,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 75, "metadata": { "slideshow": { "slide_type": "-" @@ -2173,7 +2288,7 @@ "[0, 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 70, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -2195,7 +2310,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 76, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2208,7 +2323,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 77, "metadata": { "slideshow": { "slide_type": "-" @@ -2221,7 +2336,7 @@ "[100, 100, 100, [40, 50]]" ] }, - "execution_count": 72, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -2232,7 +2347,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 78, "metadata": { "slideshow": { "slide_type": "-" @@ -2245,7 +2360,7 @@ "4" ] }, - "execution_count": 73, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -2262,12 +2377,12 @@ } }, "source": [ - "The `list` object's identity does *not* change. That is the whole point behind mutable objects." + "The `list` object's identity does *not* change. That is the main point behind mutable objects." ] }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 79, "metadata": { "slideshow": { "slide_type": "skip" @@ -2277,10 +2392,10 @@ { "data": { "text/plain": [ - "140322034424136" + "140157873498184" ] }, - "execution_count": 74, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -2297,12 +2412,12 @@ } }, "source": [ - "`nested_copy` is still unchanged!" + "`nested_copy` is unchanged!" ] }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 80, "metadata": { "slideshow": { "slide_type": "slide" @@ -2315,7 +2430,7 @@ "[[], 10, 20.0, 'Thirty', [40, 50]]" ] }, - "execution_count": 75, + "execution_count": 80, "metadata": {}, "output_type": "execute_result" } @@ -2337,7 +2452,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 81, "metadata": { "slideshow": { "slide_type": "-" @@ -2350,7 +2465,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 82, "metadata": { "slideshow": { "slide_type": "-" @@ -2363,7 +2478,7 @@ "[[], 10, 20.0, 'Thirty', [1, 2, 3]]" ] }, - "execution_count": 77, + "execution_count": 82, "metadata": {}, "output_type": "execute_result" } @@ -2380,12 +2495,12 @@ } }, "source": [ - "This has a surprising side effect on `nested`!" + "That has a surprising side effect on `nested`." ] }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 83, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2398,7 +2513,7 @@ "[100, 100, 100, [1, 2, 3]]" ] }, - "execution_count": 78, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -2415,14 +2530,14 @@ } }, "source": [ - "That is because `nested_copy` is a shallow copy of `nested`. [PythonTutor](http://pythontutor.com/visualize.html#code=nested%20%3D%20%5B%5B%5D,%2010,%2020.0,%20%22Thirty%22,%20%5B40,%2050%5D%5D%0Anested_copy%20%3D%20nested%5B%3A%5D%0Anested%5B%3A4%5D%20%3D%20%5B100,%20100,%20100%5D%0Anested_copy%5B-1%5D%5B%3A%5D%20%3D%20%5B1,%202,%203%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how both point to the *same* nested `list` object.\n", + "That is precisely the confusion we talked about above when we said that `nested_copy` is a *shallow* copy of `nested`. [PythonTutor](http://pythontutor.com/visualize.html#code=nested%20%3D%20%5B%5B%5D,%2010,%2020.0,%20%22Thirty%22,%20%5B40,%2050%5D%5D%0Anested_copy%20%3D%20nested%5B%3A%5D%0Anested%5B%3A4%5D%20%3D%20%5B100,%20100,%20100%5D%0Anested_copy%5B-1%5D%5B%3A%5D%20%3D%20%5B1,%202,%203%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how both reference the *same* nested `list` object that is changed *in place* from `[40, 50]` into `[1, 2, 3]`.\n", "\n", "Lastly, we use the `del` statement to remove an element." ] }, { "cell_type": "code", - "execution_count": 79, + "execution_count": 84, "metadata": { "slideshow": { "slide_type": "slide" @@ -2433,138 +2548,6 @@ "del nested[-1]" ] }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[100, 100, 100]" - ] - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nested" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The `del` statement, of course, also works for slices." - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "del nested[:2]" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[100]" - ] - }, - "execution_count": 82, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nested" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### List Operations" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "As with `str` objects, the `+` and `*` operators are overloaded for concatenation and always return *new* `list` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "first = [10, 20, 30]\n", - "second = [40, 50, 60]" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[10, 20, 30, 40, 50, 60]" - ] - }, - "execution_count": 84, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "first + second" - ] - }, { "cell_type": "code", "execution_count": 85, @@ -2577,7 +2560,7 @@ { "data": { "text/plain": [ - "[10, 20, 30, 10, 20, 30]" + "[100, 100, 100]" ] }, "execution_count": 85, @@ -2586,31 +2569,7 @@ } ], "source": [ - "2 * first" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[40, 50, 60, 40, 50, 60, 40, 50, 60]" - ] - }, - "execution_count": 86, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "second * 3" + "nested" ] }, { @@ -2621,9 +2580,20 @@ } }, "source": [ - "Besides being an operator, the `*` symbol has a second syntactical use, as explained in [PEP 3132](https://www.python.org/dev/peps/pep-3132/) and [PEP 448](https://www.python.org/dev/peps/pep-0448/): It implements what is called **iterable unpacking**. It is *not* an operator syntactically but a notation that Python processes as a literal.\n", - "\n", - "In the example, Python interprets the expression as if the elements of the iterable `second` were placed between `30` and `70` one by one. So, we do not obtain a nested but a *flat* list." + "The `del` statement also works for slices. Here, we remove all references `nested` holds." + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "del nested[:]" ] }, { @@ -2631,14 +2601,14 @@ "execution_count": 87, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ - "[30, 40, 50, 60, 70]" + "[]" ] }, "execution_count": 87, @@ -2647,7 +2617,44 @@ } ], "source": [ - "[30, *second, 70]" + "nested" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Mutability for sequences is formalized by the `MutableSequence` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module.\n", + "\n", + "So, we can als \"ask\" Python if `nested` is mutable." + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "isinstance(nested, abc.MutableSequence)" ] }, { @@ -2669,16 +2676,16 @@ } }, "source": [ - "The `list` type is an essential data structure in any real-world Python application, and many typical `list` related algorithms from computer science theory are already built into it at the C level (cf., the [documentation](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) for a full overview). So, understanding and applying the built-in methods of the `list` type not only speeds up the development process but also makes programs significantly faster.\n", + "The `list` type is an essential data structure in any real-world Python application, and many typical `list`-related algorithms from computer science theory are already built into it at the C level (cf., the [documentation](https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types) or the [tutorial](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) for a full overview; unfortunately, not all methods have direct links). So, understanding and applying the built-in methods of the `list` type not only speeds up the development process but also makes programs significantly faster.\n", "\n", - "In contrast to the `str` type's methods, the `list` type's methods *always* mutate (i.e., \"change\") an object *in place*. They do *not* create a *new* `list` object and return `None` to indicate that. So, we must *never* assign the return value of `list` methods to the variable holding the list!\n", + "In contrast to the `str` type's methods in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb#String-Methods) (e.g., [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) or [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower)), the `list` type's methods that mutate an object do so *in place*. That means they *never* create *new* `list` objects and return `None` to indicate that. So, we must *never* assign the return value of `list` methods to the variable holding the list!\n", "\n", "Let's look at the following `names` example." ] }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 89, "metadata": { "slideshow": { "slide_type": "slide" @@ -2686,7 +2693,7 @@ }, "outputs": [], "source": [ - "names = [\"Carl\", \"Berthold\", \"Achim\", \"Xavier\", \"Peter\"]" + "names = [\"Carl\", \"Peter\"]" ] }, { @@ -2697,12 +2704,12 @@ } }, "source": [ - "To add an object to the end of `names`, we use the append() method. The code cell shows no output indicating that `None` must have been returned." + "To add an object to the end of `names`, we use the `append()` method. The code cell shows no output indicating that `None` must be the return value." ] }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 90, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2715,7 +2722,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 91, "metadata": { "slideshow": { "slide_type": "-" @@ -2725,10 +2732,10 @@ { "data": { "text/plain": [ - "['Carl', 'Berthold', 'Achim', 'Xavier', 'Peter', 'Eckardt']" + "['Carl', 'Peter', 'Eckardt']" ] }, - "execution_count": 90, + "execution_count": 91, "metadata": {}, "output_type": "execute_result" } @@ -2745,12 +2752,12 @@ } }, "source": [ - "With the extend() method, we may also append multiple elements provided by an iterable at once. Here, the iterable is a `list` object itself holding two `str` objects." + "With the `extend()` method, we may also append multiple elements provided by an iterable. Here, the iterable is a `list` object itself holding two `str` objects." ] }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 92, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2763,7 +2770,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 93, "metadata": { "slideshow": { "slide_type": "-" @@ -2773,10 +2780,10 @@ { "data": { "text/plain": [ - "['Carl', 'Berthold', 'Achim', 'Xavier', 'Peter', 'Eckardt', 'Karl', 'Oliver']" + "['Carl', 'Peter', 'Eckardt', 'Karl', 'Oliver']" ] }, - "execution_count": 92, + "execution_count": 93, "metadata": {}, "output_type": "execute_result" } @@ -2793,36 +2800,25 @@ } }, "source": [ - "`list` objects may be sorted *in place* with the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method. That is different from the built-in [sorted()](https://docs.python.org/3/library/functions.html#sorted) function that takes any *finite* and *iterable* object and returns a *new* `list` object with the iterable's elements sorted." - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Achim', 'Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter', 'Xavier']" - ] - }, - "execution_count": 93, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted(names)" + "Similar to `append()`, we may add a new element at an arbitrary position with the `insert()` method. `insert()` takes two arguments, an *index* and the element to be inserted." ] }, { "cell_type": "code", "execution_count": 94, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "names.insert(1, \"Berthold\")" + ] + }, + { + "cell_type": "code", + "execution_count": 95, "metadata": { "slideshow": { "slide_type": "-" @@ -2832,10 +2828,10 @@ { "data": { "text/plain": [ - "['Carl', 'Berthold', 'Achim', 'Xavier', 'Peter', 'Eckardt', 'Karl', 'Oliver']" + "['Carl', 'Berthold', 'Peter', 'Eckardt', 'Karl', 'Oliver']" ] }, - "execution_count": 94, + "execution_count": 95, "metadata": {}, "output_type": "execute_result" } @@ -2844,9 +2840,90 @@ "names" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`list` objects may be sorted *in place* with the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method. That is different from the built-in [sorted()](https://docs.python.org/3/library/functions.html#sorted) function that takes any *finite* and *iterable* object and returns a *new* `list` object with the iterable's elements sorted!" + ] + }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 96, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter']" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(names)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As the previous code cell created a *new* `list` object, `names` is still unsorted." + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Carl', 'Berthold', 'Peter', 'Eckardt', 'Karl', 'Oliver']" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Let's sort the elements in `names` instead." + ] + }, + { + "cell_type": "code", + "execution_count": 98, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2859,7 +2936,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 99, "metadata": { "slideshow": { "slide_type": "-" @@ -2869,10 +2946,10 @@ { "data": { "text/plain": [ - "['Achim', 'Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter', 'Xavier']" + "['Berthold', 'Carl', 'Eckardt', 'Karl', 'Oliver', 'Peter']" ] }, - "execution_count": 96, + "execution_count": 99, "metadata": {}, "output_type": "execute_result" } @@ -2889,12 +2966,12 @@ } }, "source": [ - "To sort in reverse order, we pass a keyword-only `reverse=True` argument to either the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method or the [sorted()](https://docs.python.org/3/library/functions.html#sorted) function. In the latter case, we could also use the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in instead; however, that *neither* returns a new `list` object *nor* changes the existing one in place. We revisit it at the end of this chapter." + "To sort in reverse order, we pass a keyword-only `reverse=True` argument to either the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method or the [sorted()](https://docs.python.org/3/library/functions.html#sorted) function." ] }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 100, "metadata": { "slideshow": { "slide_type": "slide" @@ -2907,7 +2984,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 101, "metadata": { "slideshow": { "slide_type": "-" @@ -2917,10 +2994,10 @@ { "data": { "text/plain": [ - "['Xavier', 'Peter', 'Oliver', 'Karl', 'Eckardt', 'Carl', 'Berthold', 'Achim']" + "['Peter', 'Oliver', 'Karl', 'Eckardt', 'Carl', 'Berthold']" ] }, - "execution_count": 98, + "execution_count": 101, "metadata": {}, "output_type": "execute_result" } @@ -2937,14 +3014,18 @@ } }, "source": [ - "Both, the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method and the [sorted()](https://docs.python.org/3/library/functions.html#sorted) function, also accept a keyword-only `key` argument that must be a reference to a `function` object accepting one positional argument. Then, the elements in the `list` object are passed to that on a one-by-one basis, and the return values are used as the **sort keys**.\n", + "The [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method and the [sorted()](https://docs.python.org/3/library/functions.html#sorted) function sort the elements in `names` in alphabetical order, forward or backward. However, that does *not* hold in general.\n", + "\n", + "We mention above that `list` objects may contain objects of *any* type and even of *mixed* types. Because of that, the sorting is **[delegated](https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming))** to the elements in a `list` object. In a way, Python \"asks\" the elements in a `list` object to sort themselves. As `names` contains only `str` objects, they are sorted according the the comparison rules explained in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb#String-Comparison).\n", + "\n", + "To customize the sorting, we pass a keyword-only `key` argument to [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) or [sorted()](https://docs.python.org/3/library/functions.html#sorted), which must be a `function` object accepting *one* positional argument. Then, the elements in the `list` object are passed to that one by one, and the return values are used as the **sort keys**. The `key` argument is also a popular use case for `lambda` expressions.\n", "\n", "For example, to sort `names` not by alphabet but by the names' lengths, we pass in a reference to the built-in [len()](https://docs.python.org/3/library/functions.html#len) function as `key=len`. Note that there are *no* parentheses after `len`!" ] }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 102, "metadata": { "slideshow": { "slide_type": "fragment" @@ -2963,103 +3044,9 @@ } }, "source": [ - "If two names have the same length, their relative order is kept as is. A [sorting algorithm](https://en.wikipedia.org/wiki/Sorting_algorithm) is called **[stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability)** if it has that property. That is why `\"Karl\"` comes before `\"Carl\" ` below.\n", + "If two names have the same length, their relative order is kept as is. That is why `\"Karl\"` comes before `\"Carl\" ` below. A [sorting algorithm](https://en.wikipedia.org/wiki/Sorting_algorithm) with that property is called **[stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability)**.\n", "\n", - "Sorting is an important topic in programming and we refer to the official [HOWTO](https://docs.python.org/3/howto/sorting.html) for a more comprehensive introduction." - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Karl', 'Carl', 'Peter', 'Achim', 'Xavier', 'Oliver', 'Eckardt', 'Berthold']" - ] - }, - "execution_count": 100, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The pop() method removes the last element from a `list` object *and* returns it." - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'Berthold'" - ] - }, - "execution_count": 101, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names.pop()" - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Karl', 'Carl', 'Peter', 'Achim', 'Xavier', 'Oliver', 'Eckardt']" - ] - }, - "execution_count": 102, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "It takes an optional index argument and removes that instead." + "Sorting is an important topic in programming, and we refer to the official [HOWTO](https://docs.python.org/3/howto/sorting.html) for a more comprehensive introduction." ] }, { @@ -3067,14 +3054,14 @@ "execution_count": 103, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ - "'Carl'" + "['Karl', 'Carl', 'Peter', 'Oliver', 'Eckardt', 'Berthold']" ] }, "execution_count": 103, @@ -3083,12 +3070,36 @@ } ], "source": [ - "names.pop(1)" + "names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`sort(reverse=True)` is different from the `reverse()` method. Whereas the former applies some sorting rule in reverse order, the latter simply reverses the elements in a `list` object." ] }, { "cell_type": "code", "execution_count": 104, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "names.reverse()" + ] + }, + { + "cell_type": "code", + "execution_count": 105, "metadata": { "slideshow": { "slide_type": "-" @@ -3098,10 +3109,10 @@ { "data": { "text/plain": [ - "['Karl', 'Peter', 'Achim', 'Xavier', 'Oliver', 'Eckardt']" + "['Berthold', 'Eckardt', 'Oliver', 'Peter', 'Carl', 'Karl']" ] }, - "execution_count": 104, + "execution_count": 105, "metadata": {}, "output_type": "execute_result" } @@ -3118,12 +3129,158 @@ } }, "source": [ - "Instead of removing an element by its index, we can remove it by its value with the remove() method. Behind the scenes, Python then compares the object passed as its argument, `\"Peter\"` in the example, sequentially to each element with the `==` operator and removes the first one that evaluates equal." + "The `pop()` method removes the *last* element from a `list` object *and* returns it. Below we **capture** the `removed` element to show that the return value is not `None` as with all the methods introduced so far." ] }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 106, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "removed = names.pop()" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Karl'" + ] + }, + "execution_count": 107, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "removed" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Eckardt', 'Oliver', 'Peter', 'Carl']" + ] + }, + "execution_count": 108, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`pop()` takes an optional *index* argument and removes that instead.\n", + "\n", + "So, to remove the second element, `\"Eckhardt\"`, from `names`, we write this." + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "removed = names.pop(1)" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Eckardt'" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "removed" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Peter', 'Carl']" + ] + }, + "execution_count": 111, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Instead of removing an element by its index, we can also remove it by its value with the `remove()` method. Behind the scenes, Python then compares the object to be removed, `\"Peter\"` in the example, sequentially to each element with the `==` operator and removes the *first* one that evaluates equal to it. `remove()` does *not* return the removed element." + ] + }, + { + "cell_type": "code", + "execution_count": 112, "metadata": { "slideshow": { "slide_type": "slide" @@ -3136,7 +3293,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 113, "metadata": { "slideshow": { "slide_type": "-" @@ -3146,10 +3303,10 @@ { "data": { "text/plain": [ - "['Karl', 'Achim', 'Xavier', 'Oliver', 'Eckardt']" + "['Berthold', 'Oliver', 'Carl']" ] }, - "execution_count": 106, + "execution_count": 113, "metadata": {}, "output_type": "execute_result" } @@ -3166,12 +3323,12 @@ } }, "source": [ - "remove() raises a `ValueError` if the value is not found." + "Also, `remove()` raises a `ValueError` if the value is not found." ] }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 114, "metadata": { "slideshow": { "slide_type": "skip" @@ -3185,7 +3342,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Peter\"\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Peter\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: list.remove(x): x not in list" ] } @@ -3202,211 +3359,7 @@ } }, "source": [ - "`list` objects implement an index() method that returns the position of the first occurrence of an element. It fails loudly with a `ValueError` if the element cannot be found by value." - ] - }, - { - "cell_type": "code", - "execution_count": 108, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Karl', 'Achim', 'Xavier', 'Oliver', 'Eckardt']" - ] - }, - "execution_count": 108, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 109, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names.index(\"Oliver\")" - ] - }, - { - "cell_type": "code", - "execution_count": 110, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "ValueError", - "evalue": "'Carl' is not in list", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Carl\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mValueError\u001b[0m: 'Carl' is not in list" - ] - } - ], - "source": [ - "names.index(\"Carl\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The count() method returns the number of occurrences of a value." - ] - }, - { - "cell_type": "code", - "execution_count": 111, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 111, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names.count(\"Xavier\")" - ] - }, - { - "cell_type": "code", - "execution_count": 112, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 112, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names.count(\"Yves\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "### List Comparison" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The relational operators also work with `list` objects; yet another example of operator overloading.\n", - "\n", - "Comparison is made in a pairwise fashion until the first pair of elements does not evaluate equal or one of the `list` objects ends. The exact comparison rules depend on the elements and not the `list` object. We say that comparison is **[delegated](https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming))** to the objects to be compared. Usually, all elements are of the *same* type. Then, the comparison is straightforward and conceptually the same as for string comparison in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb#String-Comparison)." - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Karl', 'Achim', 'Xavier', 'Oliver', 'Eckardt']" - ] - }, - "execution_count": 113, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": { - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 114, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "names < [\"Karl\", \"Achim\", \"Oliver\", \"Xavier\", \"Eckardt\"]" + "`list` objects implement an `index()` method that returns the position of the first element that compares equal to its argument. It fails *loudly* with a `ValueError` if no element compares equal." ] }, { @@ -3414,14 +3367,14 @@ "execution_count": 115, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "slide" } }, "outputs": [ { "data": { "text/plain": [ - "True" + "['Berthold', 'Oliver', 'Carl']" ] }, "execution_count": 115, @@ -3430,18 +3383,7 @@ } ], "source": [ - "names < [\"Karl\", \"Xavier\", \"Achim\", \"Oliver\", \"Eckardt\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "The shorter `list` object is considered \"smaller,\" and vice versa." + "names" ] }, { @@ -3456,7 +3398,7 @@ { "data": { "text/plain": [ - "False" + "1" ] }, "execution_count": 116, @@ -3465,7 +3407,7 @@ } ], "source": [ - "names < [\"Karl\", \"Achim\", \"Xavier\", \"Oliver\"]" + "names.index(\"Oliver\")" ] }, { @@ -3476,20 +3418,597 @@ "slide_type": "-" } }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "'Karl' is not in list", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnames\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Karl\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mValueError\u001b[0m: 'Karl' is not in list" + ] + } + ], + "source": [ + "names.index(\"Karl\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The `count()` method returns the number of elements that compare equal to its argument." + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, "outputs": [ { "data": { "text/plain": [ - "True" + "1" ] }, - "execution_count": 117, + "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "names < [\"Karl\", \"Achim\", \"Xavier\", \"Oliver\", \"Eckardt\", \"Peter\"]" + "names.count(\"Carl\")" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 119, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names.count(\"Karl\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Two more methods, `copy()` and `clear()`, are *syntactic sugar* and replace working with slices.\n", + "\n", + "`copy()` creates a *shallow* copy. So, `names.copy()` below does the same as taking a full slice with `names[:]`, and the caveats from above apply, too." + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "names_copy = names.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Carl']" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names_copy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "`clear()` removes all references from a `list` object. So, `names_copy.clear()` is the same as `del names_copy[:]`." + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "names_copy.clear()" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 123, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names_copy" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Many methods introduced in this section are mentioned in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module's documentation as well: While the `index()` and `count()` methods come with any data type that is a `Sequence`, the `append()`, `extend()`, `insert()`, `reverse()`, `pop()`, and `remove()` methods are part of any `MutableSequence` type. The `sort()`, `copy()`, and `clear()` methods are `list`-specific.\n", + "\n", + "So, being a sequence does not only imply the four *behaviors* specified above, but also means that a data type comes with certain standardized methods." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### List Operations" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As with `str` objects, the `+` and `*` operators are overloaded for concatenation and always return a *new* `list` object. The references in this newly created `list` object reference the *same* objects as the two original `list` objects. So, the same caveat as with *shallow* copies from above applies!" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Carl']" + ] + }, + "execution_count": 124, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "more_names = [\"Diedrich\", \"Yves\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Carl', 'Diedrich', 'Yves']" + ] + }, + "execution_count": 126, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names + more_names" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Carl', 'Berthold', 'Oliver', 'Carl']" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2 * names" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Diedrich', 'Yves', 'Diedrich', 'Yves', 'Diedrich', 'Yves']" + ] + }, + "execution_count": 128, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "more_names * 3" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Besides being an operator, the `*` symbol has a second syntactical use, as explained in [PEP 3132](https://www.python.org/dev/peps/pep-3132/) and [PEP 448](https://www.python.org/dev/peps/pep-0448/): It implements what is called **iterable unpacking**. It is *not* an operator syntactically but a notation that Python reads as a literal.\n", + "\n", + "In the example, Python interprets the expression as if the elements of the iterable `names` were placed between `\"Achim\"` and `\"Xavier\"` one by one. So, we do not obtain a nested but a *flat* list." + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Achim', 'Berthold', 'Oliver', 'Carl', 'Xavier']" + ] + }, + "execution_count": 129, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[\"Achim\", *names, \"Xavier\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Effectively, Python reads that as if we wrote the following." + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Achim', 'Berthold', 'Oliver', 'Carl', 'Xavier']" + ] + }, + "execution_count": 130, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[\"Achim\", names[0], names[1], names[2], \"Xavier\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### List Comparison" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The relational operators also work with `list` objects; yet another example of operator overloading.\n", + "\n", + "Comparison is made in a pairwise fashion until the first pair of elements does not evaluate equal or one of the `list` objects ends. The exact comparison rules depend on the elements and not the `list` objects. As with [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) or [sorted()](https://docs.python.org/3/library/functions.html#sorted) above, comparison is *delegated* to the objects to be compared, and Python \"asks\" the elements in the two `list` objects to compare themselves. Usually, all elements are of the *same* type, and comparison is straightforward." + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Berthold', 'Oliver', 'Carl']" + ] + }, + "execution_count": 131, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 132, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names == [\"Berthold\", \"Oliver\", \"Carl\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 133, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names != [\"Berthold\", \"Oliver\", \"Karl\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 134, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names < [\"Berthold\", \"Oliver\", \"Karl\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 135, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[\"Achim\", \"Oliver\", \"Carl\"] < names" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "If two `list` objects have a different number of elements and all overlapping elements compare equal, the shorter `list` object is considered \"smaller.\" That rule is a common cause for *semantic* errors in a program." + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 136, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[\"Berthold\", \"Oliver\"] < names" + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 137, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "names < [\"Berthold\", \"Oliver\", \"Carl\", \"Xavier\"]" ] }, { @@ -3518,7 +4037,7 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 138, "metadata": { "slideshow": { "slide_type": "slide" @@ -3531,7 +4050,7 @@ }, { "cell_type": "code", - "execution_count": 119, + "execution_count": 139, "metadata": { "slideshow": { "slide_type": "-" @@ -3553,14 +4072,14 @@ } }, "source": [ - "While this function is being executed, two variables, namely `letters` in the global scope and `arg` inside the function's local scope, point to the *same* `list` object in memory. Furthermore, the passed in `arg` is also the return value.\n", + "While this function is being executed, two variables, namely `letters` in the global scope and `arg` inside the function's local scope, reference the *same* `list` object in memory. Furthermore, the passed in `arg` is also the return value.\n", "\n", - "So, after the function call, `letters_with_xyz` and `letters` are **aliases** as well, pointing to the *same* object." + "So, after the function call, `letters_with_xyz` and `letters` are **aliases** as well, referencing the *same* object." ] }, { "cell_type": "code", - "execution_count": 120, + "execution_count": 140, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3573,7 +4092,7 @@ }, { "cell_type": "code", - "execution_count": 121, + "execution_count": 141, "metadata": { "slideshow": { "slide_type": "-" @@ -3586,7 +4105,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 121, + "execution_count": 141, "metadata": {}, "output_type": "execute_result" } @@ -3597,7 +4116,7 @@ }, { "cell_type": "code", - "execution_count": 122, + "execution_count": 142, "metadata": { "slideshow": { "slide_type": "-" @@ -3610,7 +4129,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 122, + "execution_count": 142, "metadata": {}, "output_type": "execute_result" } @@ -3636,7 +4155,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 143, "metadata": { "slideshow": { "slide_type": "slide" @@ -3649,7 +4168,7 @@ }, { "cell_type": "code", - "execution_count": 124, + "execution_count": 144, "metadata": { "slideshow": { "slide_type": "-" @@ -3666,7 +4185,7 @@ }, { "cell_type": "code", - "execution_count": 125, + "execution_count": 145, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3679,7 +4198,7 @@ }, { "cell_type": "code", - "execution_count": 126, + "execution_count": 146, "metadata": { "scrolled": true, "slideshow": { @@ -3693,7 +4212,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 126, + "execution_count": 146, "metadata": {}, "output_type": "execute_result" } @@ -3704,7 +4223,7 @@ }, { "cell_type": "code", - "execution_count": 127, + "execution_count": 147, "metadata": { "slideshow": { "slide_type": "-" @@ -3717,7 +4236,7 @@ "['a', 'b', 'c']" ] }, - "execution_count": 127, + "execution_count": 147, "metadata": {}, "output_type": "execute_result" } @@ -3739,7 +4258,7 @@ }, { "cell_type": "code", - "execution_count": 128, + "execution_count": 148, "metadata": { "slideshow": { "slide_type": "slide" @@ -3752,7 +4271,7 @@ }, { "cell_type": "code", - "execution_count": 129, + "execution_count": 149, "metadata": { "slideshow": { "slide_type": "-" @@ -3768,7 +4287,7 @@ }, { "cell_type": "code", - "execution_count": 130, + "execution_count": 150, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3781,7 +4300,7 @@ }, { "cell_type": "code", - "execution_count": 131, + "execution_count": 151, "metadata": { "slideshow": { "slide_type": "-" @@ -3794,7 +4313,7 @@ "['a', 'b', 'c', 'x', 'y', 'z']" ] }, - "execution_count": 131, + "execution_count": 151, "metadata": {}, "output_type": "execute_result" } @@ -3816,7 +4335,7 @@ }, { "cell_type": "code", - "execution_count": 132, + "execution_count": 152, "metadata": { "slideshow": { "slide_type": "skip" @@ -3829,7 +4348,7 @@ }, { "cell_type": "code", - "execution_count": 133, + "execution_count": 153, "metadata": { "slideshow": { "slide_type": "skip" @@ -3842,7 +4361,7 @@ "['a', 'b', 'c', 'x', 'y', 'z', 'x', 'y', 'z']" ] }, - "execution_count": 133, + "execution_count": 153, "metadata": {}, "output_type": "execute_result" } @@ -3886,7 +4405,7 @@ }, { "cell_type": "code", - "execution_count": 134, + "execution_count": 154, "metadata": { "slideshow": { "slide_type": "slide" @@ -3899,7 +4418,7 @@ }, { "cell_type": "code", - "execution_count": 135, + "execution_count": 155, "metadata": { "slideshow": { "slide_type": "-" @@ -3912,7 +4431,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 135, + "execution_count": 155, "metadata": {}, "output_type": "execute_result" } @@ -3934,7 +4453,7 @@ }, { "cell_type": "code", - "execution_count": 136, + "execution_count": 156, "metadata": { "slideshow": { "slide_type": "fragment" @@ -3947,7 +4466,7 @@ }, { "cell_type": "code", - "execution_count": 137, + "execution_count": 157, "metadata": { "slideshow": { "slide_type": "-" @@ -3960,7 +4479,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 137, + "execution_count": 157, "metadata": {}, "output_type": "execute_result" } @@ -3982,20 +4501,20 @@ }, { "cell_type": "code", - "execution_count": 138, + "execution_count": 158, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ - "140322025210648" + "140157873009144" ] }, - "execution_count": 138, + "execution_count": 158, "metadata": {}, "output_type": "execute_result" } @@ -4006,10 +4525,10 @@ }, { "cell_type": "code", - "execution_count": 139, + "execution_count": 159, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4019,7 +4538,7 @@ "tuple" ] }, - "execution_count": 139, + "execution_count": 159, "metadata": {}, "output_type": "execute_result" } @@ -4041,10 +4560,10 @@ }, { "cell_type": "code", - "execution_count": 140, + "execution_count": 160, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -4054,10 +4573,10 @@ }, { "cell_type": "code", - "execution_count": 141, + "execution_count": 161, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4067,7 +4586,7 @@ "()" ] }, - "execution_count": 141, + "execution_count": 161, "metadata": {}, "output_type": "execute_result" } @@ -4078,10 +4597,10 @@ }, { "cell_type": "code", - "execution_count": 142, + "execution_count": 162, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4091,7 +4610,7 @@ "tuple" ] }, - "execution_count": 142, + "execution_count": 162, "metadata": {}, "output_type": "execute_result" } @@ -4113,10 +4632,10 @@ }, { "cell_type": "code", - "execution_count": 143, + "execution_count": 163, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [], @@ -4126,10 +4645,10 @@ }, { "cell_type": "code", - "execution_count": 144, + "execution_count": 164, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4139,7 +4658,7 @@ "(1,)" ] }, - "execution_count": 144, + "execution_count": 164, "metadata": {}, "output_type": "execute_result" } @@ -4150,10 +4669,10 @@ }, { "cell_type": "code", - "execution_count": 145, + "execution_count": 165, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -4163,7 +4682,7 @@ "tuple" ] }, - "execution_count": 145, + "execution_count": 165, "metadata": {}, "output_type": "execute_result" } @@ -4174,7 +4693,7 @@ }, { "cell_type": "code", - "execution_count": 146, + "execution_count": 166, "metadata": { "slideshow": { "slide_type": "skip" @@ -4187,7 +4706,7 @@ }, { "cell_type": "code", - "execution_count": 147, + "execution_count": 167, "metadata": { "slideshow": { "slide_type": "skip" @@ -4200,7 +4719,7 @@ "1" ] }, - "execution_count": 147, + "execution_count": 167, "metadata": {}, "output_type": "execute_result" } @@ -4211,7 +4730,7 @@ }, { "cell_type": "code", - "execution_count": 148, + "execution_count": 168, "metadata": { "slideshow": { "slide_type": "skip" @@ -4224,7 +4743,7 @@ "int" ] }, - "execution_count": 148, + "execution_count": 168, "metadata": {}, "output_type": "execute_result" } @@ -4246,10 +4765,10 @@ }, { "cell_type": "code", - "execution_count": 149, + "execution_count": 169, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -4259,7 +4778,7 @@ "(1,)" ] }, - "execution_count": 149, + "execution_count": 169, "metadata": {}, "output_type": "execute_result" } @@ -4268,6 +4787,30 @@ "tuple([1])" ] }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('i', 't', 'e', 'r', 'a', 'b', 'l', 'e')" + ] + }, + "execution_count": 170, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tuple(\"iterable\")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -4294,10 +4837,10 @@ }, { "cell_type": "code", - "execution_count": 150, + "execution_count": 171, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" } }, "outputs": [ @@ -4307,7 +4850,7 @@ "True" ] }, - "execution_count": 150, + "execution_count": 171, "metadata": {}, "output_type": "execute_result" } @@ -4329,10 +4872,10 @@ }, { "cell_type": "code", - "execution_count": 151, + "execution_count": 172, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "slide" } }, "outputs": [ @@ -4342,7 +4885,7 @@ "12" ] }, - "execution_count": 151, + "execution_count": 172, "metadata": {}, "output_type": "execute_result" } @@ -4364,7 +4907,7 @@ }, { "cell_type": "code", - "execution_count": 152, + "execution_count": 173, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4386,7 +4929,7 @@ }, { "cell_type": "code", - "execution_count": 153, + "execution_count": 174, "metadata": { "slideshow": { "slide_type": "-" @@ -4419,7 +4962,7 @@ }, { "cell_type": "code", - "execution_count": 154, + "execution_count": 175, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4432,7 +4975,7 @@ "False" ] }, - "execution_count": 154, + "execution_count": 175, "metadata": {}, "output_type": "execute_result" } @@ -4443,7 +4986,7 @@ }, { "cell_type": "code", - "execution_count": 155, + "execution_count": 176, "metadata": { "slideshow": { "slide_type": "-" @@ -4456,7 +4999,7 @@ "True" ] }, - "execution_count": 155, + "execution_count": 176, "metadata": {}, "output_type": "execute_result" } @@ -4467,7 +5010,7 @@ }, { "cell_type": "code", - "execution_count": 156, + "execution_count": 177, "metadata": { "slideshow": { "slide_type": "skip" @@ -4480,7 +5023,7 @@ "True" ] }, - "execution_count": 156, + "execution_count": 177, "metadata": {}, "output_type": "execute_result" } @@ -4502,7 +5045,7 @@ }, { "cell_type": "code", - "execution_count": 157, + "execution_count": 178, "metadata": { "slideshow": { "slide_type": "slide" @@ -4515,7 +5058,7 @@ "7" ] }, - "execution_count": 157, + "execution_count": 178, "metadata": {}, "output_type": "execute_result" } @@ -4526,7 +5069,7 @@ }, { "cell_type": "code", - "execution_count": 158, + "execution_count": 179, "metadata": { "slideshow": { "slide_type": "-" @@ -4539,7 +5082,7 @@ "4" ] }, - "execution_count": 158, + "execution_count": 179, "metadata": {}, "output_type": "execute_result" } @@ -4550,7 +5093,7 @@ }, { "cell_type": "code", - "execution_count": 159, + "execution_count": 180, "metadata": { "slideshow": { "slide_type": "-" @@ -4563,7 +5106,7 @@ "(2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 159, + "execution_count": 180, "metadata": {}, "output_type": "execute_result" } @@ -4585,7 +5128,7 @@ }, { "cell_type": "code", - "execution_count": 160, + "execution_count": 181, "metadata": { "slideshow": { "slide_type": "slide" @@ -4599,7 +5142,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnumbers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m99\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnumbers\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m99\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } @@ -4616,44 +5159,31 @@ } }, "source": [ - "If we need to \"modify\" the `tuple` object, we must create a *new* `tuple` object, for example, like so: We take a slice of the elements we want to keep and use the overloaded `+` operator to concatenate the slice with another `tuple` object." + "We can verify the immutability with the `MutableSequence` ABC from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module: [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) returns `False`. So, a data type that is a `Sequence` may be mutable or not. If it is a `MutableSequence`, it is mutable. If it is *not* a `MutableSequence`, it is *immutable*. There is *no* `ImmutableSequence` ABC." ] }, { "cell_type": "code", - "execution_count": 161, + "execution_count": 182, "metadata": { "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "new_numbers = numbers[:-1] + (99,)" - ] - }, - { - "cell_type": "code", - "execution_count": 162, - "metadata": { - "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ { "data": { "text/plain": [ - "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 99)" + "False" ] }, - "execution_count": 162, + "execution_count": 182, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "new_numbers" + "isinstance(numbers, abc.MutableSequence)" ] }, { @@ -4664,17 +5194,44 @@ } }, "source": [ - "The `*` operator works as well." + "The `+` and `*` operators work with `tuple` objects as well. However, we should *not* do that as the whole point of immutability is to *not* mutate an object.\n", + "\n", + "So, instead of writing something like below, we should use a `list` object and call its `append()` method." ] }, { "cell_type": "code", - "execution_count": 163, + "execution_count": 183, "metadata": { "slideshow": { "slide_type": "skip" } }, + "outputs": [ + { + "data": { + "text/plain": [ + "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4, 99)" + ] + }, + "execution_count": 183, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers + (99,) " + ] + }, + { + "cell_type": "code", + "execution_count": 184, + "metadata": { + "scrolled": false, + "slideshow": { + "slide_type": "skip" + } + }, "outputs": [ { "data": { @@ -4682,7 +5239,7 @@ "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4, 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" ] }, - "execution_count": 163, + "execution_count": 184, "metadata": {}, "output_type": "execute_result" } @@ -4699,12 +5256,12 @@ } }, "source": [ - "Being immutable, `tuple` objects only provide the count() and index() methods." + "Being immutable, `tuple` objects only provide the `count()` and `index()` methods of `Sequence` types. The `append()`, `extend()`, `insert()`, `reverse()`, `pop()`, and `remove()` methods of `MutableSequence` types are *not* available. The same holds for the `list`-specific methods `sort()`, `copy()`, and `clear()`." ] }, { "cell_type": "code", - "execution_count": 164, + "execution_count": 185, "metadata": { "slideshow": { "slide_type": "skip" @@ -4717,7 +5274,7 @@ "0" ] }, - "execution_count": 164, + "execution_count": 185, "metadata": {}, "output_type": "execute_result" } @@ -4728,7 +5285,7 @@ }, { "cell_type": "code", - "execution_count": 165, + "execution_count": 186, "metadata": { "slideshow": { "slide_type": "skip" @@ -4741,7 +5298,7 @@ "10" ] }, - "execution_count": 165, + "execution_count": 186, "metadata": {}, "output_type": "execute_result" } @@ -4758,15 +5315,39 @@ } }, "source": [ - "The relational operators compare the elements of two `tuple` objects in a pairwise fashion as above." + "The relational operators work in the *same* way as for `list` objects." ] }, { "cell_type": "code", - "execution_count": 166, + "execution_count": 187, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" + ] + }, + "execution_count": 187, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 188, + "metadata": { + "slideshow": { + "slide_type": "skip" } }, "outputs": [ @@ -4776,13 +5357,85 @@ "True" ] }, - "execution_count": 166, + "execution_count": 188, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "numbers < new_numbers" + "numbers == (7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 189, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 189, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers != (99, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 190, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers < (99, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 191, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 191, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(0, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4) < numbers" ] }, { @@ -4795,15 +5448,15 @@ "source": [ "While `tuple` objects are immutable, this only relates to the references they hold. If a `tuple` object contains mutable objects, the entire nested structure is *not* immutable as a whole.\n", "\n", - "Consider the following stylized example `not_immutable`: It contains *three* elements, `1`, `[2, ..., 11]`, and `12`, and the elements of the nested `list` object may be changed. While it is not practical to mix data types in a `tuple` object that is used as an \"immutable list,\" we want to make the point that the mere usage of the `tuple` type does *not* guarantee a nested object to be immutable." + "Consider the following stylized example `not_immutable`: It contains *three* elements, `1`, `[2, ..., 11]`, and `12`, and the elements of the nested `list` object may be changed. While it is not practical to mix data types in a `tuple` object that is used as an \"immutable list,\" we want to make the point that the mere usage of the `tuple` type does *not* guarantee a nested object to be immutable as a whole." ] }, { "cell_type": "code", - "execution_count": 167, + "execution_count": 192, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "outputs": [], @@ -4813,10 +5466,34 @@ }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 193, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 12)" + ] + }, + "execution_count": 193, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "not_immutable" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "metadata": { + "slideshow": { + "slide_type": "fragment" } }, "outputs": [], @@ -4826,10 +5503,10 @@ }, { "cell_type": "code", - "execution_count": 169, + "execution_count": 195, "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "-" } }, "outputs": [ @@ -4839,7 +5516,7 @@ "(1, [99, 99, 99], 12)" ] }, - "execution_count": 169, + "execution_count": 195, "metadata": {}, "output_type": "execute_result" } @@ -4874,7 +5551,7 @@ }, { "cell_type": "code", - "execution_count": 170, + "execution_count": 196, "metadata": { "slideshow": { "slide_type": "slide" @@ -4887,7 +5564,7 @@ }, { "cell_type": "code", - "execution_count": 171, + "execution_count": 197, "metadata": { "slideshow": { "slide_type": "fragment" @@ -4900,7 +5577,7 @@ "7" ] }, - "execution_count": 171, + "execution_count": 197, "metadata": {}, "output_type": "execute_result" } @@ -4911,7 +5588,7 @@ }, { "cell_type": "code", - "execution_count": 172, + "execution_count": 198, "metadata": { "slideshow": { "slide_type": "-" @@ -4924,7 +5601,7 @@ "11" ] }, - "execution_count": 172, + "execution_count": 198, "metadata": {}, "output_type": "execute_result" } @@ -4935,7 +5612,7 @@ }, { "cell_type": "code", - "execution_count": 173, + "execution_count": 199, "metadata": { "slideshow": { "slide_type": "-" @@ -4948,7 +5625,7 @@ "8" ] }, - "execution_count": 173, + "execution_count": 199, "metadata": {}, "output_type": "execute_result" } @@ -4970,7 +5647,7 @@ }, { "cell_type": "code", - "execution_count": 174, + "execution_count": 200, "metadata": { "slideshow": { "slide_type": "skip" @@ -4984,7 +5661,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: too many values to unpack (expected 11)" ] } @@ -4995,7 +5672,7 @@ }, { "cell_type": "code", - "execution_count": 175, + "execution_count": 201, "metadata": { "slideshow": { "slide_type": "skip" @@ -5009,7 +5686,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn12\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn13\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mn1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn6\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn7\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn8\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn11\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn12\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn13\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumbers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: not enough values to unpack (expected 13, got 12)" ] } @@ -5033,7 +5710,7 @@ }, { "cell_type": "code", - "execution_count": 176, + "execution_count": 202, "metadata": { "slideshow": { "slide_type": "slide" @@ -5046,7 +5723,7 @@ }, { "cell_type": "code", - "execution_count": 177, + "execution_count": 203, "metadata": { "slideshow": { "slide_type": "-" @@ -5059,7 +5736,7 @@ "7" ] }, - "execution_count": 177, + "execution_count": 203, "metadata": {}, "output_type": "execute_result" } @@ -5070,7 +5747,7 @@ }, { "cell_type": "code", - "execution_count": 178, + "execution_count": 204, "metadata": { "slideshow": { "slide_type": "-" @@ -5083,7 +5760,7 @@ "[11, 8, 5, 3, 12, 2, 6, 9, 10, 1]" ] }, - "execution_count": 178, + "execution_count": 204, "metadata": {}, "output_type": "execute_result" } @@ -5094,7 +5771,7 @@ }, { "cell_type": "code", - "execution_count": 179, + "execution_count": 205, "metadata": { "slideshow": { "slide_type": "-" @@ -5107,7 +5784,7 @@ "4" ] }, - "execution_count": 179, + "execution_count": 205, "metadata": {}, "output_type": "execute_result" } @@ -5129,7 +5806,7 @@ }, { "cell_type": "code", - "execution_count": 180, + "execution_count": 206, "metadata": { "slideshow": { "slide_type": "skip" @@ -5142,7 +5819,7 @@ }, { "cell_type": "code", - "execution_count": 181, + "execution_count": 207, "metadata": { "slideshow": { "slide_type": "skip" @@ -5155,7 +5832,7 @@ "7" ] }, - "execution_count": 181, + "execution_count": 207, "metadata": {}, "output_type": "execute_result" } @@ -5166,7 +5843,7 @@ }, { "cell_type": "code", - "execution_count": 182, + "execution_count": 208, "metadata": { "slideshow": { "slide_type": "skip" @@ -5179,7 +5856,7 @@ "4" ] }, - "execution_count": 182, + "execution_count": 208, "metadata": {}, "output_type": "execute_result" } @@ -5203,7 +5880,7 @@ }, { "cell_type": "code", - "execution_count": 183, + "execution_count": 209, "metadata": { "slideshow": { "slide_type": "slide" @@ -5216,7 +5893,7 @@ }, { "cell_type": "code", - "execution_count": 184, + "execution_count": 210, "metadata": { "slideshow": { "slide_type": "-" @@ -5227,11 +5904,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Karl is a goalkeeper\n", - "Achim is a defender\n", - "Xavier is a midfielder\n", - "Oliver is a striker\n", - "Eckardt is a coach\n" + "Berthold is a goalkeeper\n", + "Oliver is a defender\n", + "Carl is a midfielder\n" ] } ], @@ -5253,7 +5928,7 @@ }, { "cell_type": "code", - "execution_count": 185, + "execution_count": 211, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5264,11 +5939,9 @@ "name": "stdout", "output_type": "stream", "text": [ - " ('Karl', 'goalkeeper')\n", - " ('Achim', 'defender')\n", - " ('Xavier', 'midfielder')\n", - " ('Oliver', 'striker')\n", - " ('Eckardt', 'coach')\n" + " ('Berthold', 'goalkeeper')\n", + " ('Oliver', 'defender')\n", + " ('Carl', 'midfielder')\n" ] } ], @@ -5290,7 +5963,7 @@ }, { "cell_type": "code", - "execution_count": 186, + "execution_count": 212, "metadata": { "slideshow": { "slide_type": "skip" @@ -5301,11 +5974,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "0 -> Karl is a goalkeeper\n", - "1 -> Achim is a defender\n", - "2 -> Xavier is a midfielder\n", - "3 -> Oliver is a striker\n", - "4 -> Eckardt is a coach\n" + "0 -> Berthold is a goalkeeper\n", + "1 -> Oliver is a defender\n", + "2 -> Carl is a midfielder\n" ] } ], @@ -5340,7 +6011,7 @@ }, { "cell_type": "code", - "execution_count": 187, + "execution_count": 213, "metadata": { "slideshow": { "slide_type": "slide" @@ -5365,7 +6036,7 @@ }, { "cell_type": "code", - "execution_count": 188, + "execution_count": 214, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5380,7 +6051,7 @@ }, { "cell_type": "code", - "execution_count": 189, + "execution_count": 215, "metadata": { "slideshow": { "slide_type": "-" @@ -5393,7 +6064,7 @@ "(1, 0)" ] }, - "execution_count": 189, + "execution_count": 215, "metadata": {}, "output_type": "execute_result" } @@ -5415,7 +6086,7 @@ }, { "cell_type": "code", - "execution_count": 190, + "execution_count": 216, "metadata": { "slideshow": { "slide_type": "slide" @@ -5429,7 +6100,7 @@ }, { "cell_type": "code", - "execution_count": 191, + "execution_count": 217, "metadata": { "slideshow": { "slide_type": "-" @@ -5442,7 +6113,7 @@ }, { "cell_type": "code", - "execution_count": 192, + "execution_count": 218, "metadata": { "slideshow": { "slide_type": "-" @@ -5455,7 +6126,7 @@ "(1, 0)" ] }, - "execution_count": 192, + "execution_count": 218, "metadata": {}, "output_type": "execute_result" } @@ -5488,7 +6159,7 @@ }, { "cell_type": "code", - "execution_count": 193, + "execution_count": 219, "metadata": { "slideshow": { "slide_type": "skip" @@ -5501,7 +6172,7 @@ }, { "cell_type": "code", - "execution_count": 194, + "execution_count": 220, "metadata": { "slideshow": { "slide_type": "skip" @@ -5519,12 +6190,17 @@ " ith_fibonacci (int)\n", "\n", " Raises:\n", - " TypeError: if i is not an integer\n", + " TypeError: if i is not an integer or not integer-like\n", " ValueError: if i is not positive\n", " \"\"\"\n", " if not isinstance(i, numbers.Integral):\n", - " raise TypeError(\"i must be an integer\")\n", - " elif i < 0:\n", + " if isinstance(i, numbers.Real):\n", + " if i != int(i):\n", + " raise TypeError(\"i is not an integer-like value; it has decimals\")\n", + " i = int(i)\n", + " else:\n", + " raise TypeError(\"i must be an integer\")\n", + " if i < 0:\n", " raise ValueError(\"i must be non-negative\")\n", "\n", " a, b = 0, 1\n", @@ -5537,7 +6213,7 @@ }, { "cell_type": "code", - "execution_count": 195, + "execution_count": 221, "metadata": { "slideshow": { "slide_type": "skip" @@ -5550,7 +6226,7 @@ "144" ] }, - "execution_count": 195, + "execution_count": 221, "metadata": {}, "output_type": "execute_result" } @@ -5559,6 +6235,67 @@ "fibonacci(12)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Because of the *goose typing*, we may pass `float` objects to `fibonacci()` as long as they contain no decimals." + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "144" + ] + }, + "execution_count": 222, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fibonacci(12.0)" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "i is not an integer-like value; it has decimals", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m12.3\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\u001b[0m in \u001b[0;36mfibonacci\u001b[0;34m(i)\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\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 16\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\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[0;32m---> 17\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"i 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 18\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\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: i is not an integer-like value; it has decimals" + ] + } + ], + "source": [ + "fibonacci(12.3)" + ] + }, { "cell_type": "markdown", "metadata": { @@ -5587,7 +6324,7 @@ }, { "cell_type": "code", - "execution_count": 196, + "execution_count": 224, "metadata": { "slideshow": { "slide_type": "slide" @@ -5620,7 +6357,7 @@ }, { "cell_type": "code", - "execution_count": 197, + "execution_count": 225, "metadata": { "slideshow": { "slide_type": "-" @@ -5633,7 +6370,7 @@ "42" ] }, - "execution_count": 197, + "execution_count": 225, "metadata": {}, "output_type": "execute_result" } @@ -5655,7 +6392,7 @@ }, { "cell_type": "code", - "execution_count": 198, + "execution_count": 226, "metadata": { "slideshow": { "slide_type": "-" @@ -5668,7 +6405,7 @@ "100" ] }, - "execution_count": 198, + "execution_count": 226, "metadata": {}, "output_type": "execute_result" } @@ -5690,7 +6427,7 @@ }, { "cell_type": "code", - "execution_count": 199, + "execution_count": 227, "metadata": { "slideshow": { "slide_type": "slide" @@ -5704,8 +6441,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mproduct\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[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mproduct\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Multiply all arguments.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\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[0m\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0marg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\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[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mproduct\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[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mproduct\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mproduct\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\"\"\"Multiply all arguments.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0margs\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[0m\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0marg\u001b[0m \u001b[0;32min\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\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[0;31mIndexError\u001b[0m: tuple index out of range" ] } @@ -5727,7 +6464,7 @@ }, { "cell_type": "code", - "execution_count": 200, + "execution_count": 228, "metadata": { "slideshow": { "slide_type": "slide" @@ -5740,7 +6477,7 @@ }, { "cell_type": "code", - "execution_count": 201, + "execution_count": 229, "metadata": { "slideshow": { "slide_type": "-" @@ -5753,7 +6490,7 @@ "[2, 5, 10]" ] }, - "execution_count": 201, + "execution_count": 229, "metadata": {}, "output_type": "execute_result" } @@ -5775,7 +6512,7 @@ }, { "cell_type": "code", - "execution_count": 202, + "execution_count": 230, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5788,7 +6525,7 @@ "100" ] }, - "execution_count": 202, + "execution_count": 230, "metadata": {}, "output_type": "execute_result" } @@ -5810,7 +6547,7 @@ }, { "cell_type": "code", - "execution_count": 203, + "execution_count": 231, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5823,7 +6560,7 @@ "100" ] }, - "execution_count": 203, + "execution_count": 231, "metadata": {}, "output_type": "execute_result" } @@ -5840,6 +6577,8 @@ } }, "source": [ + "In the \"*Packing & Unpacking with Functions*\" [exercise](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_review_and_exercises.ipynb#Packing-&-Unpacking-with-Functions) at the end of this chapter, we look at `product()` in more detail.\n", + "\n", "While we needed to unpack `one_hundred` above to avoid the semantic error, unpacking an argument in a function call may also be a convenience in general.\n", "\n", "For example, to print the elements of `one_hundred` in one line, we need to use a `for` statement, until now. With unpacking, we get away *without* a loop." @@ -5847,7 +6586,7 @@ }, { "cell_type": "code", - "execution_count": 204, + "execution_count": 232, "metadata": { "slideshow": { "slide_type": "skip" @@ -5868,7 +6607,7 @@ }, { "cell_type": "code", - "execution_count": 205, + "execution_count": 233, "metadata": { "slideshow": { "slide_type": "skip" @@ -5890,7 +6629,7 @@ }, { "cell_type": "code", - "execution_count": 206, + "execution_count": 234, "metadata": { "slideshow": { "slide_type": "skip" @@ -5906,7 +6645,7 @@ } ], "source": [ - "print(*one_hundred)" + "print(*one_hundred) # replaces the for-loop" ] }, { @@ -5917,7 +6656,7 @@ } }, "source": [ - "## The `namedtuple` Type" + "### The `namedtuple` Type" ] }, { @@ -5939,7 +6678,7 @@ }, { "cell_type": "code", - "execution_count": 207, + "execution_count": 235, "metadata": { "slideshow": { "slide_type": "slide" @@ -5965,7 +6704,7 @@ }, { "cell_type": "code", - "execution_count": 208, + "execution_count": 236, "metadata": { "slideshow": { "slide_type": "fragment" @@ -5989,7 +6728,7 @@ }, { "cell_type": "code", - "execution_count": 209, + "execution_count": 237, "metadata": { "slideshow": { "slide_type": "-" @@ -6013,7 +6752,7 @@ }, { "cell_type": "code", - "execution_count": 210, + "execution_count": 238, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6023,10 +6762,10 @@ { "data": { "text/plain": [ - "140321614839000" + "140157466523464" ] }, - "execution_count": 210, + "execution_count": 238, "metadata": {}, "output_type": "execute_result" } @@ -6037,7 +6776,7 @@ }, { "cell_type": "code", - "execution_count": 211, + "execution_count": 239, "metadata": { "slideshow": { "slide_type": "-" @@ -6050,7 +6789,7 @@ "type" ] }, - "execution_count": 211, + "execution_count": 239, "metadata": {}, "output_type": "execute_result" } @@ -6067,12 +6806,47 @@ } }, "source": [ - "To create a `Point` object, we use the same *literal syntax* as for `current_position` above and prepend it with `Point`." + "The value of `Point` is just itself in a *literal notation*." ] }, { "cell_type": "code", - "execution_count": 212, + "execution_count": 240, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "__main__.Point" + ] + }, + "execution_count": 240, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Point" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "We write `Point(4, 2)` to create a *new* object of type `Point`." + ] + }, + { + "cell_type": "code", + "execution_count": 241, "metadata": { "slideshow": { "slide_type": "slide" @@ -6096,7 +6870,7 @@ }, { "cell_type": "code", - "execution_count": 213, + "execution_count": 242, "metadata": { "slideshow": { "slide_type": "-" @@ -6109,7 +6883,7 @@ "Point(x=4, y=2)" ] }, - "execution_count": 213, + "execution_count": 242, "metadata": {}, "output_type": "execute_result" } @@ -6131,7 +6905,7 @@ }, { "cell_type": "code", - "execution_count": 214, + "execution_count": 243, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6141,10 +6915,10 @@ { "data": { "text/plain": [ - "140322025282656" + "140157872590424" ] }, - "execution_count": 214, + "execution_count": 243, "metadata": {}, "output_type": "execute_result" } @@ -6155,7 +6929,7 @@ }, { "cell_type": "code", - "execution_count": 215, + "execution_count": 244, "metadata": { "slideshow": { "slide_type": "-" @@ -6168,7 +6942,7 @@ "__main__.Point" ] }, - "execution_count": 215, + "execution_count": 244, "metadata": {}, "output_type": "execute_result" } @@ -6190,7 +6964,7 @@ }, { "cell_type": "code", - "execution_count": 216, + "execution_count": 245, "metadata": { "slideshow": { "slide_type": "slide" @@ -6203,7 +6977,7 @@ "4" ] }, - "execution_count": 216, + "execution_count": 245, "metadata": {}, "output_type": "execute_result" } @@ -6214,7 +6988,7 @@ }, { "cell_type": "code", - "execution_count": 217, + "execution_count": 246, "metadata": { "slideshow": { "slide_type": "-" @@ -6227,7 +7001,7 @@ "2" ] }, - "execution_count": 217, + "execution_count": 246, "metadata": {}, "output_type": "execute_result" } @@ -6249,7 +7023,7 @@ }, { "cell_type": "code", - "execution_count": 218, + "execution_count": 247, "metadata": { "slideshow": { "slide_type": "skip" @@ -6263,7 +7037,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcurrent_position\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcurrent_position\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Point' object has no attribute 'z'" ] } @@ -6287,7 +7061,7 @@ }, { "cell_type": "code", - "execution_count": 219, + "execution_count": 248, "metadata": { "slideshow": { "slide_type": "slide" @@ -6300,7 +7074,7 @@ "True" ] }, - "execution_count": 219, + "execution_count": 248, "metadata": {}, "output_type": "execute_result" } @@ -6311,7 +7085,7 @@ }, { "cell_type": "code", - "execution_count": 220, + "execution_count": 249, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6324,7 +7098,7 @@ "4" ] }, - "execution_count": 220, + "execution_count": 249, "metadata": {}, "output_type": "execute_result" } @@ -6335,7 +7109,7 @@ }, { "cell_type": "code", - "execution_count": 221, + "execution_count": 250, "metadata": { "slideshow": { "slide_type": "-" @@ -6348,7 +7122,7 @@ "2" ] }, - "execution_count": 221, + "execution_count": 250, "metadata": {}, "output_type": "execute_result" } @@ -6359,7 +7133,7 @@ }, { "cell_type": "code", - "execution_count": 222, + "execution_count": 251, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6382,7 +7156,7 @@ }, { "cell_type": "code", - "execution_count": 223, + "execution_count": 252, "metadata": { "slideshow": { "slide_type": "skip" @@ -6429,7 +7203,7 @@ }, { "cell_type": "code", - "execution_count": 224, + "execution_count": 253, "metadata": { "slideshow": { "slide_type": "slide" @@ -6466,7 +7240,7 @@ }, { "cell_type": "code", - "execution_count": 225, + "execution_count": 254, "metadata": { "slideshow": { "slide_type": "slide" @@ -6492,7 +7266,7 @@ }, { "cell_type": "code", - "execution_count": 226, + "execution_count": 255, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6509,7 +7283,7 @@ }, { "cell_type": "code", - "execution_count": 227, + "execution_count": 256, "metadata": { "slideshow": { "slide_type": "-" @@ -6522,7 +7296,7 @@ "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" ] }, - "execution_count": 227, + "execution_count": 256, "metadata": {}, "output_type": "execute_result" } @@ -6546,7 +7320,7 @@ }, { "cell_type": "code", - "execution_count": 228, + "execution_count": 257, "metadata": { "slideshow": { "slide_type": "slide" @@ -6570,7 +7344,7 @@ }, { "cell_type": "code", - "execution_count": 229, + "execution_count": 258, "metadata": { "slideshow": { "slide_type": "-" @@ -6580,10 +7354,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 229, + "execution_count": 258, "metadata": {}, "output_type": "execute_result" } @@ -6594,7 +7368,7 @@ }, { "cell_type": "code", - "execution_count": 230, + "execution_count": 259, "metadata": { "slideshow": { "slide_type": "-" @@ -6607,7 +7381,7 @@ "map" ] }, - "execution_count": 230, + "execution_count": 259, "metadata": {}, "output_type": "execute_result" } @@ -6631,7 +7405,7 @@ }, { "cell_type": "code", - "execution_count": 231, + "execution_count": 260, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6644,7 +7418,7 @@ "50" ] }, - "execution_count": 231, + "execution_count": 260, "metadata": {}, "output_type": "execute_result" } @@ -6655,7 +7429,7 @@ }, { "cell_type": "code", - "execution_count": 232, + "execution_count": 261, "metadata": { "slideshow": { "slide_type": "skip" @@ -6668,7 +7442,7 @@ "122" ] }, - "execution_count": 232, + "execution_count": 261, "metadata": {}, "output_type": "execute_result" } @@ -6679,7 +7453,7 @@ }, { "cell_type": "code", - "execution_count": 233, + "execution_count": 262, "metadata": { "slideshow": { "slide_type": "skip" @@ -6692,7 +7466,7 @@ "65" ] }, - "execution_count": 233, + "execution_count": 262, "metadata": {}, "output_type": "execute_result" } @@ -6716,7 +7490,7 @@ }, { "cell_type": "code", - "execution_count": 234, + "execution_count": 263, "metadata": { "slideshow": { "slide_type": "slide" @@ -6729,7 +7503,7 @@ }, { "cell_type": "code", - "execution_count": 235, + "execution_count": 264, "metadata": { "slideshow": { "slide_type": "-" @@ -6742,7 +7516,7 @@ "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" ] }, - "execution_count": 235, + "execution_count": 264, "metadata": {}, "output_type": "execute_result" } @@ -6777,7 +7551,7 @@ }, { "cell_type": "code", - "execution_count": 236, + "execution_count": 265, "metadata": { "slideshow": { "slide_type": "slide" @@ -6805,7 +7579,7 @@ }, { "cell_type": "code", - "execution_count": 237, + "execution_count": 266, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6822,7 +7596,7 @@ }, { "cell_type": "code", - "execution_count": 238, + "execution_count": 267, "metadata": { "slideshow": { "slide_type": "-" @@ -6835,7 +7609,7 @@ "[50, 122, 26, 10, 82, 2]" ] }, - "execution_count": 238, + "execution_count": 267, "metadata": {}, "output_type": "execute_result" } @@ -6857,7 +7631,7 @@ }, { "cell_type": "code", - "execution_count": 239, + "execution_count": 268, "metadata": { "slideshow": { "slide_type": "slide" @@ -6870,7 +7644,7 @@ }, { "cell_type": "code", - "execution_count": 240, + "execution_count": 269, "metadata": { "slideshow": { "slide_type": "-" @@ -6880,10 +7654,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 240, + "execution_count": 269, "metadata": {}, "output_type": "execute_result" } @@ -6894,7 +7668,7 @@ }, { "cell_type": "code", - "execution_count": 241, + "execution_count": 270, "metadata": { "slideshow": { "slide_type": "-" @@ -6907,7 +7681,7 @@ "filter" ] }, - "execution_count": 241, + "execution_count": 270, "metadata": {}, "output_type": "execute_result" } @@ -6929,7 +7703,7 @@ }, { "cell_type": "code", - "execution_count": 242, + "execution_count": 271, "metadata": { "slideshow": { "slide_type": "fragment" @@ -6942,7 +7716,7 @@ "[50, 122, 65, 26, 10, 145, 5, 37, 82, 101, 2, 17]" ] }, - "execution_count": 242, + "execution_count": 271, "metadata": {}, "output_type": "execute_result" } @@ -6953,7 +7727,7 @@ }, { "cell_type": "code", - "execution_count": 243, + "execution_count": 272, "metadata": { "slideshow": { "slide_type": "-" @@ -6966,7 +7740,7 @@ "50" ] }, - "execution_count": 243, + "execution_count": 272, "metadata": {}, "output_type": "execute_result" } @@ -6977,7 +7751,7 @@ }, { "cell_type": "code", - "execution_count": 244, + "execution_count": 273, "metadata": { "slideshow": { "slide_type": "skip" @@ -6990,7 +7764,7 @@ "122" ] }, - "execution_count": 244, + "execution_count": 273, "metadata": {}, "output_type": "execute_result" } @@ -7001,7 +7775,7 @@ }, { "cell_type": "code", - "execution_count": 245, + "execution_count": 274, "metadata": { "slideshow": { "slide_type": "skip" @@ -7014,7 +7788,7 @@ "26" ] }, - "execution_count": 245, + "execution_count": 274, "metadata": {}, "output_type": "execute_result" } @@ -7036,7 +7810,7 @@ }, { "cell_type": "code", - "execution_count": 246, + "execution_count": 275, "metadata": { "slideshow": { "slide_type": "slide" @@ -7049,7 +7823,7 @@ "[50, 122, 26, 10, 82, 2]" ] }, - "execution_count": 246, + "execution_count": 275, "metadata": {}, "output_type": "execute_result" } @@ -7071,7 +7845,7 @@ }, { "cell_type": "code", - "execution_count": 247, + "execution_count": 276, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7084,7 +7858,7 @@ "[50, 122, 26, 10, 82, 2]" ] }, - "execution_count": 247, + "execution_count": 276, "metadata": {}, "output_type": "execute_result" } @@ -7106,7 +7880,7 @@ }, { "cell_type": "code", - "execution_count": 248, + "execution_count": 277, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7119,7 +7893,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 248, + "execution_count": 277, "metadata": {}, "output_type": "execute_result" } @@ -7154,7 +7928,7 @@ }, { "cell_type": "code", - "execution_count": 249, + "execution_count": 278, "metadata": { "slideshow": { "slide_type": "slide" @@ -7167,7 +7941,7 @@ "370" ] }, - "execution_count": 249, + "execution_count": 278, "metadata": {}, "output_type": "execute_result" } @@ -7189,7 +7963,7 @@ }, { "cell_type": "code", - "execution_count": 250, + "execution_count": 279, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7202,7 +7976,7 @@ "5" ] }, - "execution_count": 250, + "execution_count": 279, "metadata": {}, "output_type": "execute_result" } @@ -7213,7 +7987,7 @@ }, { "cell_type": "code", - "execution_count": 251, + "execution_count": 280, "metadata": { "slideshow": { "slide_type": "-" @@ -7226,7 +8000,7 @@ "145" ] }, - "execution_count": 251, + "execution_count": 280, "metadata": {}, "output_type": "execute_result" } @@ -7252,7 +8026,7 @@ }, { "cell_type": "code", - "execution_count": 252, + "execution_count": 281, "metadata": { "slideshow": { "slide_type": "slide" @@ -7278,7 +8052,7 @@ }, { "cell_type": "code", - "execution_count": 253, + "execution_count": 282, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7304,7 +8078,7 @@ }, { "cell_type": "code", - "execution_count": 254, + "execution_count": 283, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7340,7 +8114,7 @@ }, { "cell_type": "code", - "execution_count": 255, + "execution_count": 284, "metadata": { "slideshow": { "slide_type": "-" @@ -7353,7 +8127,7 @@ "370" ] }, - "execution_count": 255, + "execution_count": 284, "metadata": {}, "output_type": "execute_result" } @@ -7377,7 +8151,7 @@ }, { "cell_type": "code", - "execution_count": 256, + "execution_count": 285, "metadata": { "slideshow": { "slide_type": "slide" @@ -7390,7 +8164,7 @@ }, { "cell_type": "code", - "execution_count": 257, + "execution_count": 286, "metadata": { "slideshow": { "slide_type": "-" @@ -7403,7 +8177,7 @@ "370" ] }, - "execution_count": 257, + "execution_count": 286, "metadata": {}, "output_type": "execute_result" } @@ -7433,16 +8207,16 @@ "source": [ "[map()](https://docs.python.org/3/library/functions.html#map), [filter()](https://docs.python.org/3/library/functions.html#filter), and [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) take a `function` object as their first argument, and we defined `transform()`, `is_even()`, and `add()` to be used precisely for that.\n", "\n", - "Often, such functions are used *only once* in a program. However, the primary purpose of functions is to *re-use* them. In such cases, it makes more sense to define them \"anonymously\" right at the position where the first argument goes.\n", + "Often, such functions are used *only once* in a program. However, the primary purpose of functions is to *reuse* them. In such cases, it makes more sense to define them \"anonymously\" right at the position where the first argument goes.\n", "\n", - "As mentioned in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb#Anonymous-Functions), Python provides `lambda` expressions to create `function` objects *without* a variable pointing to them.\n", + "As mentioned in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb#Anonymous-Functions), Python provides `lambda` expressions to create `function` objects *without* a name referencing them.\n", "\n", "So, the above `add()` function could be rewritten as a `lambda` expression like so ..." ] }, { "cell_type": "code", - "execution_count": 258, + "execution_count": 287, "metadata": { "slideshow": { "slide_type": "slide" @@ -7455,7 +8229,7 @@ "(sum_so_far, next_number)>" ] }, - "execution_count": 258, + "execution_count": 287, "metadata": {}, "output_type": "execute_result" } @@ -7477,7 +8251,7 @@ }, { "cell_type": "code", - "execution_count": 259, + "execution_count": 288, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7490,7 +8264,7 @@ "(x, y)>" ] }, - "execution_count": 259, + "execution_count": 288, "metadata": {}, "output_type": "execute_result" } @@ -7512,7 +8286,7 @@ }, { "cell_type": "code", - "execution_count": 260, + "execution_count": 289, "metadata": { "slideshow": { "slide_type": "slide" @@ -7525,7 +8299,7 @@ "370" ] }, - "execution_count": 260, + "execution_count": 289, "metadata": {}, "output_type": "execute_result" } @@ -7550,7 +8324,7 @@ }, { "cell_type": "code", - "execution_count": 261, + "execution_count": 290, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7563,7 +8337,7 @@ "370" ] }, - "execution_count": 261, + "execution_count": 290, "metadata": {}, "output_type": "execute_result" } @@ -7588,7 +8362,7 @@ }, { "cell_type": "code", - "execution_count": 262, + "execution_count": 291, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7601,7 +8375,7 @@ "370" ] }, - "execution_count": 262, + "execution_count": 291, "metadata": {}, "output_type": "execute_result" } @@ -7654,7 +8428,7 @@ }, { "cell_type": "code", - "execution_count": 263, + "execution_count": 292, "metadata": { "slideshow": { "slide_type": "slide" @@ -7667,7 +8441,7 @@ }, { "cell_type": "code", - "execution_count": 264, + "execution_count": 293, "metadata": { "slideshow": { "slide_type": "-" @@ -7684,7 +8458,7 @@ }, { "cell_type": "code", - "execution_count": 265, + "execution_count": 294, "metadata": { "slideshow": { "slide_type": "-" @@ -7697,7 +8471,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 265, + "execution_count": 294, "metadata": {}, "output_type": "execute_result" } @@ -7719,7 +8493,7 @@ }, { "cell_type": "code", - "execution_count": 266, + "execution_count": 295, "metadata": { "slideshow": { "slide_type": "slide" @@ -7732,7 +8506,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 266, + "execution_count": 295, "metadata": {}, "output_type": "execute_result" } @@ -7756,7 +8530,7 @@ }, { "cell_type": "code", - "execution_count": 267, + "execution_count": 296, "metadata": { "slideshow": { "slide_type": "fragment" @@ -7769,7 +8543,7 @@ "370" ] }, - "execution_count": 267, + "execution_count": 296, "metadata": {}, "output_type": "execute_result" } @@ -7804,7 +8578,7 @@ }, { "cell_type": "code", - "execution_count": 268, + "execution_count": 297, "metadata": { "slideshow": { "slide_type": "skip" @@ -7817,7 +8591,7 @@ }, { "cell_type": "code", - "execution_count": 269, + "execution_count": 298, "metadata": { "slideshow": { "slide_type": "skip" @@ -7830,7 +8604,7 @@ "[[1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6, 7, 8, 9]]" ] }, - "execution_count": 269, + "execution_count": 298, "metadata": {}, "output_type": "execute_result" } @@ -7854,7 +8628,7 @@ }, { "cell_type": "code", - "execution_count": 270, + "execution_count": 299, "metadata": { "slideshow": { "slide_type": "skip" @@ -7871,7 +8645,7 @@ }, { "cell_type": "code", - "execution_count": 271, + "execution_count": 300, "metadata": { "slideshow": { "slide_type": "skip" @@ -7884,7 +8658,7 @@ "[1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9]" ] }, - "execution_count": 271, + "execution_count": 300, "metadata": {}, "output_type": "execute_result" } @@ -7906,7 +8680,7 @@ }, { "cell_type": "code", - "execution_count": 272, + "execution_count": 301, "metadata": { "slideshow": { "slide_type": "skip" @@ -7919,7 +8693,7 @@ "[1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 8, 9]" ] }, - "execution_count": 272, + "execution_count": 301, "metadata": {}, "output_type": "execute_result" } @@ -7943,7 +8717,7 @@ }, { "cell_type": "code", - "execution_count": 273, + "execution_count": 302, "metadata": { "slideshow": { "slide_type": "skip" @@ -7956,7 +8730,7 @@ "105" ] }, - "execution_count": 273, + "execution_count": 302, "metadata": {}, "output_type": "execute_result" } @@ -7978,7 +8752,7 @@ }, { "cell_type": "code", - "execution_count": 274, + "execution_count": 303, "metadata": { "slideshow": { "slide_type": "skip" @@ -7991,7 +8765,7 @@ "105" ] }, - "execution_count": 274, + "execution_count": 303, "metadata": {}, "output_type": "execute_result" } @@ -8034,7 +8808,7 @@ }, { "cell_type": "code", - "execution_count": 275, + "execution_count": 304, "metadata": { "slideshow": { "slide_type": "skip" @@ -8059,7 +8833,7 @@ }, { "cell_type": "code", - "execution_count": 276, + "execution_count": 305, "metadata": { "slideshow": { "slide_type": "skip" @@ -8072,7 +8846,7 @@ "[1.25, 1.2, 1.1666666666666667, 1.5, 1.4, 1.3333333333333333, 1.75, 1.6, 1.5]" ] }, - "execution_count": 276, + "execution_count": 305, "metadata": {}, "output_type": "execute_result" } @@ -8101,7 +8875,7 @@ }, { "cell_type": "code", - "execution_count": 277, + "execution_count": 306, "metadata": { "slideshow": { "slide_type": "skip" @@ -8114,7 +8888,7 @@ "[1.25, 1.2, 1.1666666666666667, 1.5, 1.4, 1.3333333333333333, 1.75, 1.6, 1.5]" ] }, - "execution_count": 277, + "execution_count": 306, "metadata": {}, "output_type": "execute_result" } @@ -8136,7 +8910,7 @@ }, { "cell_type": "code", - "execution_count": 278, + "execution_count": 307, "metadata": { "slideshow": { "slide_type": "skip" @@ -8149,7 +8923,7 @@ "[5.0, 3.0, 2.333333333333333, 6.0, 3.5, 2.666666666666667, 7.0, 4.0, 3.0]" ] }, - "execution_count": 278, + "execution_count": 307, "metadata": {}, "output_type": "execute_result" } @@ -8171,7 +8945,7 @@ }, { "cell_type": "code", - "execution_count": 279, + "execution_count": 308, "metadata": { "slideshow": { "slide_type": "skip" @@ -8184,7 +8958,7 @@ "20.58" ] }, - "execution_count": 279, + "execution_count": 308, "metadata": {}, "output_type": "execute_result" } @@ -8206,7 +8980,7 @@ }, { "cell_type": "code", - "execution_count": 280, + "execution_count": 309, "metadata": { "slideshow": { "slide_type": "skip" @@ -8219,7 +8993,7 @@ "20.58" ] }, - "execution_count": 280, + "execution_count": 309, "metadata": {}, "output_type": "execute_result" } @@ -8265,7 +9039,7 @@ }, { "cell_type": "code", - "execution_count": 281, + "execution_count": 310, "metadata": { "slideshow": { "slide_type": "slide" @@ -8289,7 +9063,7 @@ }, { "cell_type": "code", - "execution_count": 282, + "execution_count": 311, "metadata": { "slideshow": { "slide_type": "-" @@ -8302,7 +9076,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 282, + "execution_count": 311, "metadata": {}, "output_type": "execute_result" } @@ -8324,7 +9098,7 @@ }, { "cell_type": "code", - "execution_count": 283, + "execution_count": 312, "metadata": { "slideshow": { "slide_type": "fragment" @@ -8334,10 +9108,10 @@ { "data": { "text/plain": [ - " at 0x7f9f447618b8>" + " at 0x7f790c3a55e8>" ] }, - "execution_count": 283, + "execution_count": 312, "metadata": {}, "output_type": "execute_result" } @@ -8361,7 +9135,7 @@ }, { "cell_type": "code", - "execution_count": 284, + "execution_count": 313, "metadata": { "slideshow": { "slide_type": "fragment" @@ -8374,7 +9148,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 284, + "execution_count": 313, "metadata": {}, "output_type": "execute_result" } @@ -8396,7 +9170,7 @@ }, { "cell_type": "code", - "execution_count": 285, + "execution_count": 314, "metadata": { "slideshow": { "slide_type": "fragment" @@ -8409,7 +9183,7 @@ "[65, 145, 5, 37, 101, 17]" ] }, - "execution_count": 285, + "execution_count": 314, "metadata": {}, "output_type": "execute_result" } @@ -8431,7 +9205,7 @@ }, { "cell_type": "code", - "execution_count": 286, + "execution_count": 315, "metadata": { "slideshow": { "slide_type": "fragment" @@ -8444,7 +9218,7 @@ "370" ] }, - "execution_count": 286, + "execution_count": 315, "metadata": {}, "output_type": "execute_result" } @@ -8466,7 +9240,7 @@ }, { "cell_type": "code", - "execution_count": 287, + "execution_count": 316, "metadata": { "slideshow": { "slide_type": "slide" @@ -8479,7 +9253,7 @@ }, { "cell_type": "code", - "execution_count": 288, + "execution_count": 317, "metadata": { "slideshow": { "slide_type": "-" @@ -8489,10 +9263,10 @@ { "data": { "text/plain": [ - " at 0x7f9f44761d68>" + " at 0x7f790c3a5a20>" ] }, - "execution_count": 288, + "execution_count": 317, "metadata": {}, "output_type": "execute_result" } @@ -8514,7 +9288,7 @@ }, { "cell_type": "code", - "execution_count": 289, + "execution_count": 318, "metadata": { "slideshow": { "slide_type": "-" @@ -8527,7 +9301,7 @@ "generator" ] }, - "execution_count": 289, + "execution_count": 318, "metadata": {}, "output_type": "execute_result" } @@ -8549,7 +9323,7 @@ }, { "cell_type": "code", - "execution_count": 290, + "execution_count": 319, "metadata": { "slideshow": { "slide_type": "fragment" @@ -8562,7 +9336,7 @@ "65" ] }, - "execution_count": 290, + "execution_count": 319, "metadata": {}, "output_type": "execute_result" } @@ -8573,7 +9347,7 @@ }, { "cell_type": "code", - "execution_count": 291, + "execution_count": 320, "metadata": { "slideshow": { "slide_type": "skip" @@ -8586,7 +9360,7 @@ "145" ] }, - "execution_count": 291, + "execution_count": 320, "metadata": {}, "output_type": "execute_result" } @@ -8597,7 +9371,7 @@ }, { "cell_type": "code", - "execution_count": 292, + "execution_count": 321, "metadata": { "slideshow": { "slide_type": "skip" @@ -8610,7 +9384,7 @@ "5" ] }, - "execution_count": 292, + "execution_count": 321, "metadata": {}, "output_type": "execute_result" } @@ -8621,7 +9395,7 @@ }, { "cell_type": "code", - "execution_count": 293, + "execution_count": 322, "metadata": { "slideshow": { "slide_type": "skip" @@ -8634,7 +9408,7 @@ "37" ] }, - "execution_count": 293, + "execution_count": 322, "metadata": {}, "output_type": "execute_result" } @@ -8645,7 +9419,7 @@ }, { "cell_type": "code", - "execution_count": 294, + "execution_count": 323, "metadata": { "slideshow": { "slide_type": "skip" @@ -8658,7 +9432,7 @@ "101" ] }, - "execution_count": 294, + "execution_count": 323, "metadata": {}, "output_type": "execute_result" } @@ -8669,7 +9443,7 @@ }, { "cell_type": "code", - "execution_count": 295, + "execution_count": 324, "metadata": { "slideshow": { "slide_type": "skip" @@ -8682,7 +9456,7 @@ "17" ] }, - "execution_count": 295, + "execution_count": 324, "metadata": {}, "output_type": "execute_result" } @@ -8704,7 +9478,7 @@ }, { "cell_type": "code", - "execution_count": 296, + "execution_count": 325, "metadata": { "slideshow": { "slide_type": "skip" @@ -8718,7 +9492,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m: " ] } @@ -8729,7 +9503,7 @@ }, { "cell_type": "code", - "execution_count": 297, + "execution_count": 326, "metadata": { "slideshow": { "slide_type": "skip" @@ -8743,7 +9517,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgen\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m: " ] } @@ -8765,7 +9539,7 @@ }, { "cell_type": "code", - "execution_count": 298, + "execution_count": 327, "metadata": { "slideshow": { "slide_type": "skip" @@ -8813,7 +9587,7 @@ }, { "cell_type": "code", - "execution_count": 299, + "execution_count": 328, "metadata": { "slideshow": { "slide_type": "skip" @@ -8826,7 +9600,7 @@ }, { "cell_type": "code", - "execution_count": 300, + "execution_count": 329, "metadata": { "slideshow": { "slide_type": "skip" @@ -8839,7 +9613,7 @@ "[[1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6, 7, 8, 9]]" ] }, - "execution_count": 300, + "execution_count": 329, "metadata": {}, "output_type": "execute_result" } @@ -8861,7 +9635,7 @@ }, { "cell_type": "code", - "execution_count": 301, + "execution_count": 330, "metadata": { "slideshow": { "slide_type": "skip" @@ -8874,7 +9648,7 @@ "105" ] }, - "execution_count": 301, + "execution_count": 330, "metadata": {}, "output_type": "execute_result" } @@ -8896,7 +9670,7 @@ }, { "cell_type": "code", - "execution_count": 302, + "execution_count": 331, "metadata": { "slideshow": { "slide_type": "skip" @@ -8909,7 +9683,7 @@ "105" ] }, - "execution_count": 302, + "execution_count": 331, "metadata": {}, "output_type": "execute_result" } @@ -8931,7 +9705,7 @@ }, { "cell_type": "code", - "execution_count": 303, + "execution_count": 332, "metadata": { "slideshow": { "slide_type": "skip" @@ -8944,7 +9718,7 @@ }, { "cell_type": "code", - "execution_count": 304, + "execution_count": 333, "metadata": { "slideshow": { "slide_type": "skip" @@ -8954,10 +9728,10 @@ { "data": { "text/plain": [ - " at 0x7f9f44761e58>" + " at 0x7f790c3a5b10>" ] }, - "execution_count": 304, + "execution_count": 333, "metadata": {}, "output_type": "execute_result" } @@ -8968,7 +9742,7 @@ }, { "cell_type": "code", - "execution_count": 305, + "execution_count": 334, "metadata": { "slideshow": { "slide_type": "skip" @@ -8981,7 +9755,7 @@ "105" ] }, - "execution_count": 305, + "execution_count": 334, "metadata": {}, "output_type": "execute_result" } @@ -9003,7 +9777,7 @@ }, { "cell_type": "code", - "execution_count": 306, + "execution_count": 335, "metadata": { "slideshow": { "slide_type": "skip" @@ -9016,7 +9790,7 @@ "0" ] }, - "execution_count": 306, + "execution_count": 335, "metadata": {}, "output_type": "execute_result" } @@ -9051,7 +9825,7 @@ }, { "cell_type": "code", - "execution_count": 307, + "execution_count": 336, "metadata": { "slideshow": { "slide_type": "skip" @@ -9078,7 +9852,7 @@ }, { "cell_type": "code", - "execution_count": 308, + "execution_count": 337, "metadata": { "slideshow": { "slide_type": "skip" @@ -9091,7 +9865,7 @@ "20.58" ] }, - "execution_count": 308, + "execution_count": 337, "metadata": {}, "output_type": "execute_result" } @@ -9113,7 +9887,7 @@ }, { "cell_type": "code", - "execution_count": 309, + "execution_count": 338, "metadata": { "slideshow": { "slide_type": "skip" @@ -9126,7 +9900,7 @@ "20.58" ] }, - "execution_count": 309, + "execution_count": 338, "metadata": {}, "output_type": "execute_result" } @@ -9143,7 +9917,7 @@ } }, "source": [ - "In summary, we learn from this example that unpacking generator expressions may be a *bad* idea." + "In summary, we learn from this example that unpacking generator expressions *may* be a *bad* idea." ] }, { @@ -9172,7 +9946,7 @@ }, { "cell_type": "code", - "execution_count": 310, + "execution_count": 339, "metadata": { "slideshow": { "slide_type": "skip" @@ -9185,7 +9959,7 @@ "(65, 145, 5, 37, 101, 17)" ] }, - "execution_count": 310, + "execution_count": 339, "metadata": {}, "output_type": "execute_result" } @@ -9220,7 +9994,7 @@ }, { "cell_type": "code", - "execution_count": 311, + "execution_count": 340, "metadata": { "slideshow": { "slide_type": "slide" @@ -9246,7 +10020,7 @@ }, { "cell_type": "code", - "execution_count": 312, + "execution_count": 341, "metadata": { "slideshow": { "slide_type": "fragment" @@ -9259,7 +10033,7 @@ "False" ] }, - "execution_count": 312, + "execution_count": 341, "metadata": {}, "output_type": "execute_result" } @@ -9270,7 +10044,7 @@ }, { "cell_type": "code", - "execution_count": 313, + "execution_count": 342, "metadata": { "slideshow": { "slide_type": "-" @@ -9283,7 +10057,7 @@ "True" ] }, - "execution_count": 313, + "execution_count": 342, "metadata": {}, "output_type": "execute_result" } @@ -9305,7 +10079,7 @@ }, { "cell_type": "code", - "execution_count": 314, + "execution_count": 343, "metadata": { "slideshow": { "slide_type": "skip" @@ -9318,7 +10092,7 @@ "False" ] }, - "execution_count": 314, + "execution_count": 343, "metadata": {}, "output_type": "execute_result" } @@ -9349,7 +10123,7 @@ }, { "cell_type": "code", - "execution_count": 315, + "execution_count": 344, "metadata": { "slideshow": { "slide_type": "skip" @@ -9367,7 +10141,7 @@ }, { "cell_type": "code", - "execution_count": 316, + "execution_count": 345, "metadata": { "slideshow": { "slide_type": "skip" @@ -9380,7 +10154,7 @@ "False" ] }, - "execution_count": 316, + "execution_count": 345, "metadata": {}, "output_type": "execute_result" } @@ -9391,7 +10165,7 @@ }, { "cell_type": "code", - "execution_count": 317, + "execution_count": 346, "metadata": { "slideshow": { "slide_type": "skip" @@ -9404,7 +10178,7 @@ "True" ] }, - "execution_count": 317, + "execution_count": 346, "metadata": {}, "output_type": "execute_result" } @@ -9428,7 +10202,7 @@ }, { "cell_type": "code", - "execution_count": 318, + "execution_count": 347, "metadata": { "slideshow": { "slide_type": "fragment" @@ -9441,7 +10215,7 @@ "True" ] }, - "execution_count": 318, + "execution_count": 347, "metadata": {}, "output_type": "execute_result" } @@ -9452,7 +10226,7 @@ }, { "cell_type": "code", - "execution_count": 319, + "execution_count": 348, "metadata": { "slideshow": { "slide_type": "-" @@ -9465,7 +10239,7 @@ "False" ] }, - "execution_count": 319, + "execution_count": 348, "metadata": {}, "output_type": "execute_result" } @@ -9487,7 +10261,7 @@ }, { "cell_type": "code", - "execution_count": 320, + "execution_count": 349, "metadata": { "slideshow": { "slide_type": "skip" @@ -9500,7 +10274,7 @@ "True" ] }, - "execution_count": 320, + "execution_count": 349, "metadata": {}, "output_type": "execute_result" } @@ -9531,7 +10305,7 @@ }, { "cell_type": "code", - "execution_count": 321, + "execution_count": 350, "metadata": { "slideshow": { "slide_type": "skip" @@ -9549,7 +10323,7 @@ }, { "cell_type": "code", - "execution_count": 322, + "execution_count": 351, "metadata": { "slideshow": { "slide_type": "skip" @@ -9562,7 +10336,7 @@ "True" ] }, - "execution_count": 322, + "execution_count": 351, "metadata": {}, "output_type": "execute_result" } @@ -9573,7 +10347,7 @@ }, { "cell_type": "code", - "execution_count": 323, + "execution_count": 352, "metadata": { "slideshow": { "slide_type": "skip" @@ -9586,7 +10360,7 @@ "False" ] }, - "execution_count": 323, + "execution_count": 352, "metadata": {}, "output_type": "execute_result" } @@ -9625,7 +10399,7 @@ }, { "cell_type": "code", - "execution_count": 324, + "execution_count": 353, "metadata": { "slideshow": { "slide_type": "skip" @@ -9653,7 +10427,7 @@ }, { "cell_type": "code", - "execution_count": 325, + "execution_count": 354, "metadata": { "slideshow": { "slide_type": "skip" @@ -9666,7 +10440,7 @@ "7.0" ] }, - "execution_count": 325, + "execution_count": 354, "metadata": {}, "output_type": "execute_result" } @@ -9688,7 +10462,7 @@ }, { "cell_type": "code", - "execution_count": 326, + "execution_count": 355, "metadata": { "slideshow": { "slide_type": "skip" @@ -9701,7 +10475,7 @@ "7.0" ] }, - "execution_count": 326, + "execution_count": 355, "metadata": {}, "output_type": "execute_result" } @@ -9723,7 +10497,7 @@ }, { "cell_type": "code", - "execution_count": 327, + "execution_count": 356, "metadata": { "slideshow": { "slide_type": "skip" @@ -9736,7 +10510,7 @@ }, { "cell_type": "code", - "execution_count": 328, + "execution_count": 357, "metadata": { "slideshow": { "slide_type": "skip" @@ -9749,7 +10523,7 @@ }, { "cell_type": "code", - "execution_count": 329, + "execution_count": 358, "metadata": { "slideshow": { "slide_type": "skip" @@ -9762,7 +10536,7 @@ "49.994081434519636" ] }, - "execution_count": 329, + "execution_count": 358, "metadata": {}, "output_type": "execute_result" } @@ -9784,7 +10558,7 @@ }, { "cell_type": "code", - "execution_count": 330, + "execution_count": 359, "metadata": { "slideshow": { "slide_type": "skip" @@ -9798,8 +10572,8 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10_000_000\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[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36maverage_evens\u001b[0;34m(numbers)\u001b[0m\n\u001b[1;32m 12\u001b[0m total, count = reduce(\n\u001b[1;32m 13\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\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[0;32m---> 14\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mintegers\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m )\n\u001b[1;32m 16\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mtotal\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mcount\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0maverage_evens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mrandom\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrandint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m49\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10_000_000\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[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36maverage_evens\u001b[0;34m(numbers)\u001b[0m\n\u001b[1;32m 12\u001b[0m total, count = reduce(\n\u001b[1;32m 13\u001b[0m \u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\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[0;32m---> 14\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mintegers\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 15\u001b[0m )\n\u001b[1;32m 16\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mtotal\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mcount\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: reduce() of empty sequence with no initial value" ] } @@ -9831,12 +10605,12 @@ "\n", "Similarly, we have introduced data types in this chapter that all share the \"behavior\" of modeling some \"rule\" in memory to generate objects \"on the fly:\" They are the `map`, `filter`, and `generator` types. Their main commonality is supporting the built-in [next()](https://docs.python.org/3/library/functions.html#next) function. In computer science terminology, such data types are called **[iterators](https://en.wikipedia.org/wiki/Iterator)**, and the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module formalizes them with the `Iterator` ABC.\n", "\n", - "So, an example of an iterator is `evens_transformed` below, an object of type `map`." + "So, an example of an iterator is `evens_transformed` below, an object of type `generator`." ] }, { "cell_type": "code", - "execution_count": 331, + "execution_count": 360, "metadata": { "slideshow": { "slide_type": "slide" @@ -9849,7 +10623,7 @@ }, { "cell_type": "code", - "execution_count": 332, + "execution_count": 361, "metadata": { "slideshow": { "slide_type": "-" @@ -9857,7 +10631,7 @@ }, "outputs": [], "source": [ - "evens_transformed = map(lambda x: (x ** 2) + 1, filter(lambda x: x % 2 == 0, numbers))" + "evens_transformed = ((x ** 2) + 1 for x in numbers if x % 2 == 0)" ] }, { @@ -9873,7 +10647,7 @@ }, { "cell_type": "code", - "execution_count": 333, + "execution_count": 362, "metadata": { "slideshow": { "slide_type": "fragment" @@ -9886,7 +10660,7 @@ "True" ] }, - "execution_count": 333, + "execution_count": 362, "metadata": {}, "output_type": "execute_result" } @@ -9908,7 +10682,7 @@ }, { "cell_type": "code", - "execution_count": 334, + "execution_count": 363, "metadata": { "slideshow": { "slide_type": "fragment" @@ -9921,7 +10695,7 @@ "True" ] }, - "execution_count": 334, + "execution_count": 363, "metadata": {}, "output_type": "execute_result" } @@ -9949,7 +10723,7 @@ }, { "cell_type": "code", - "execution_count": 335, + "execution_count": 364, "metadata": { "slideshow": { "slide_type": "slide" @@ -9962,7 +10736,7 @@ }, { "cell_type": "code", - "execution_count": 336, + "execution_count": 365, "metadata": { "slideshow": { "slide_type": "-" @@ -9986,7 +10760,7 @@ }, { "cell_type": "code", - "execution_count": 337, + "execution_count": 366, "metadata": { "slideshow": { "slide_type": "fragment" @@ -9999,7 +10773,7 @@ "list_iterator" ] }, - "execution_count": 337, + "execution_count": 366, "metadata": {}, "output_type": "execute_result" } @@ -10023,7 +10797,7 @@ }, { "cell_type": "code", - "execution_count": 338, + "execution_count": 367, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10036,7 +10810,7 @@ "(7, 11, 8)" ] }, - "execution_count": 338, + "execution_count": 367, "metadata": {}, "output_type": "execute_result" } @@ -10058,7 +10832,7 @@ }, { "cell_type": "code", - "execution_count": 339, + "execution_count": 368, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10071,7 +10845,7 @@ "(5, 7)" ] }, - "execution_count": 339, + "execution_count": 368, "metadata": {}, "output_type": "execute_result" } @@ -10093,7 +10867,7 @@ }, { "cell_type": "code", - "execution_count": 340, + "execution_count": 369, "metadata": { "slideshow": { "slide_type": "slide" @@ -10106,7 +10880,7 @@ }, { "cell_type": "code", - "execution_count": 341, + "execution_count": 370, "metadata": { "slideshow": { "slide_type": "-" @@ -10119,7 +10893,7 @@ "(99, 99)" ] }, - "execution_count": 341, + "execution_count": 370, "metadata": {}, "output_type": "execute_result" } @@ -10141,7 +10915,7 @@ }, { "cell_type": "code", - "execution_count": 342, + "execution_count": 371, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10154,7 +10928,7 @@ }, { "cell_type": "code", - "execution_count": 343, + "execution_count": 372, "metadata": { "slideshow": { "slide_type": "-" @@ -10167,7 +10941,7 @@ "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" ] }, - "execution_count": 343, + "execution_count": 372, "metadata": {}, "output_type": "execute_result" } @@ -10178,7 +10952,7 @@ }, { "cell_type": "code", - "execution_count": 344, + "execution_count": 373, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10191,7 +10965,7 @@ "(6, 3)" ] }, - "execution_count": 344, + "execution_count": 373, "metadata": {}, "output_type": "execute_result" } @@ -10217,7 +10991,7 @@ }, { "cell_type": "code", - "execution_count": 345, + "execution_count": 374, "metadata": { "slideshow": { "slide_type": "slide" @@ -10230,7 +11004,7 @@ }, { "cell_type": "code", - "execution_count": 346, + "execution_count": 375, "metadata": { "slideshow": { "slide_type": "-" @@ -10240,10 +11014,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 346, + "execution_count": 375, "metadata": {}, "output_type": "execute_result" } @@ -10254,7 +11028,7 @@ }, { "cell_type": "code", - "execution_count": 347, + "execution_count": 376, "metadata": { "slideshow": { "slide_type": "-" @@ -10267,7 +11041,7 @@ "zip" ] }, - "execution_count": 347, + "execution_count": 376, "metadata": {}, "output_type": "execute_result" } @@ -10278,7 +11052,7 @@ }, { "cell_type": "code", - "execution_count": 348, + "execution_count": 377, "metadata": { "slideshow": { "slide_type": "-" @@ -10291,7 +11065,7 @@ "True" ] }, - "execution_count": 348, + "execution_count": 377, "metadata": {}, "output_type": "execute_result" } @@ -10313,7 +11087,7 @@ }, { "cell_type": "code", - "execution_count": 349, + "execution_count": 378, "metadata": { "slideshow": { "slide_type": "slide" @@ -10326,7 +11100,7 @@ }, { "cell_type": "code", - "execution_count": 350, + "execution_count": 379, "metadata": { "slideshow": { "slide_type": "-" @@ -10336,10 +11110,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 350, + "execution_count": 379, "metadata": {}, "output_type": "execute_result" } @@ -10356,12 +11130,12 @@ } }, "source": [ - "`zipper_iterator` points to the *same* object as `zipper`! That holds for *iterators* in general: Any *iterator* created from an existing *iterator* with [iter()](https://docs.python.org/3/library/functions.html#iter) is the *iterator* itself." + "`zipper_iterator` references the *same* object as `zipper`! That holds for *iterators* in general: Any *iterator* created from an existing *iterator* with [iter()](https://docs.python.org/3/library/functions.html#iter) is the *iterator* itself." ] }, { "cell_type": "code", - "execution_count": 351, + "execution_count": 380, "metadata": { "slideshow": { "slide_type": "-" @@ -10374,7 +11148,7 @@ "True" ] }, - "execution_count": 351, + "execution_count": 380, "metadata": {}, "output_type": "execute_result" } @@ -10393,12 +11167,12 @@ "source": [ "The Python core developers made that design decision so that *iterators* may also be looped over.\n", "\n", - "The `for`-loop below prints out *six* more `tuple` objects derived from the re-ordered `numbers` because the `iterator1` object hidden inside `zipper` already returned the first *six* elements. So, the respective first elements of the `tuple` objects printed range from `7` to `12`. Similarly, as `iterator2` already provided *three* elements from `numbers`, we see the respective second elements in the range from `4` to `9`." + "The `for`-loop below prints out *six* more `tuple` objects derived from the now ordered `numbers` because the `iterator1` object hidden inside `zipper` already returned the first *six* elements. So, the respective first elements of the `tuple` objects printed range from `7` to `12`. Similarly, as `iterator2` already provided *three* elements from `numbers`, we see the respective second elements in the range from `4` to `9`." ] }, { "cell_type": "code", - "execution_count": 352, + "execution_count": 381, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10431,7 +11205,7 @@ }, { "cell_type": "code", - "execution_count": 353, + "execution_count": 382, "metadata": { "slideshow": { "slide_type": "skip" @@ -10456,7 +11230,7 @@ }, { "cell_type": "code", - "execution_count": 354, + "execution_count": 383, "metadata": { "slideshow": { "slide_type": "fragment" @@ -10470,7 +11244,7 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterator1\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\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterator1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mStopIteration\u001b[0m: " ] } @@ -10492,7 +11266,7 @@ }, { "cell_type": "code", - "execution_count": 355, + "execution_count": 384, "metadata": { "slideshow": { "slide_type": "skip" @@ -10505,7 +11279,7 @@ "10" ] }, - "execution_count": 355, + "execution_count": 384, "metadata": {}, "output_type": "execute_result" } @@ -10514,6 +11288,17 @@ "next(iterator2)" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Understanding *iterators* and *iterables* is helpful for any data science practitioner that deals with large amounts of data. Even without that, these two terms occur everywhere in Python-related texts and documentation." + ] + }, { "cell_type": "markdown", "metadata": { @@ -10540,7 +11325,7 @@ }, { "cell_type": "code", - "execution_count": 356, + "execution_count": 385, "metadata": { "slideshow": { "slide_type": "slide" @@ -10553,7 +11338,7 @@ }, { "cell_type": "code", - "execution_count": 357, + "execution_count": 386, "metadata": { "slideshow": { "slide_type": "-" @@ -10586,10 +11371,10 @@ }, { "cell_type": "code", - "execution_count": 358, + "execution_count": 387, "metadata": { "slideshow": { - "slide_type": "fragment" + "slide_type": "skip" } }, "outputs": [ @@ -10627,10 +11412,10 @@ }, { "cell_type": "code", - "execution_count": 359, + "execution_count": 388, "metadata": { "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" } }, "outputs": [ @@ -10654,6 +11439,17 @@ " print(element, end=\" \")" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### sorted() vs. reversed()" + ] + }, { "cell_type": "markdown", "metadata": { @@ -10662,7 +11458,703 @@ } }, "source": [ - "Understanding *iterators* and *iterables* is helpful for any data science practitioner that deals with large amounts of data. Even without that, these two terms occur everywhere in Python-related texts and documentation." + "Now that we know the concept of an *iterator*, let's compare some of the built-ins introduced in this chapter in detail and make sure we understand what is going on in memory. This sub-section is thus a great summary of this chapter as well.\n", + "\n", + "We use two simple examples, `numbers` and `memoryless`, to guide us through the discussion. `numbers` creates *thirteen* objects in memory and `memoryless` only *one* (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))" + ] + }, + { + "cell_type": "code", + "execution_count": 389, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 390, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "memoryless = range(1, 13)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The [sorted()](https://docs.python.org/3/library/functions.html#sorted) function takes a *finite* and *iterable* object as its argument and *materializes* its elements into a *new* `list` object that is returned.\n", + "\n", + "The argument may already be materialized, as is the case with `numbers`, but could also be an *iterator* that generates *new* objects, such as `memoryless`. In both cases, we end up with materialized `list` objects with the elements sorted in *forward* order (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20sorted%28numbers%29%0Aresult2%20%3D%20sorted%28memoryless%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))." + ] + }, + { + "cell_type": "code", + "execution_count": 391, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" + ] + }, + "execution_count": 391, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(numbers)" + ] + }, + { + "cell_type": "code", + "execution_count": 392, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" + ] + }, + "execution_count": 392, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(memoryless)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "By adding a keyword-only argument `reverse=True`, the materialized `list` objects are sorted in *reverse* order (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20sorted%28numbers,%20reverse%3DTrue%29%0Aresult2%20%3D%20sorted%28memoryless,%20reverse%3DTrue%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false))." + ] + }, + { + "cell_type": "code", + "execution_count": 393, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" + ] + }, + "execution_count": 393, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(numbers, reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 394, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" + ] + }, + "execution_count": 394, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(memoryless, reverse=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The order in `numbers` remains *unchanged*, and `memoryless` is still *not* materialized." + ] + }, + { + "cell_type": "code", + "execution_count": 395, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + "execution_count": 395, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 396, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "range(1, 13)" + ] + }, + "execution_count": 396, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "memoryless" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in takes a *sequence* object as its argument and returns an *iterator*. The argument must be *finite* and *reversible* (i.e., *iterable* in *reverse* order) as otherwise [reversed()](https://docs.python.org/3/library/functions.html#reversed) could neither determine the last element that becomes the first nor loop in a *predictable* backward fashion. [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aiterator1%20%3D%20reversed%28numbers%29%0Aiterator2%20%3D%20reversed%28memoryless%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) confirms that [reversed()](https://docs.python.org/3/library/functions.html#reversed) does *not* materialize any elements but only returns an *iterator*.\n", + "\n", + "**Side Note**: Even though `range` objects, like `memoryless` here, do *not* \"contain\" references to other objects, they count as *sequence* types, and as such, they are also *container* types. The `in` operator works with `range` objects because we can always cast the object to be checked as an `int` and check if that lies within the `range` object's *start* and *stop* values, taking a potential *step* value into account (cf., this [blog post](https://treyhunner.com/2018/02/python-range-is-not-an-iterator/) for more details on the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in)." + ] + }, + { + "cell_type": "code", + "execution_count": 397, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 397, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reversed(numbers)" + ] + }, + { + "cell_type": "code", + "execution_count": 398, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 398, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reversed(memoryless)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "To materialize the elements, we can pass the returned *iterators* to, for example, the [list()](https://docs.python.org/3/library/functions.html#func-list) or [tuple()](https://docs.python.org/3/library/functions.html#func-tuple) built-ins. That creates *new* `list` and `tuple` objects (cf., [PythonTutor](http://www.pythontutor.com/visualize.html#code=numbers%20%3D%20%5B7,%2011,%208,%205,%203,%2012,%202,%206,%209,%2010,%201,%204%5D%0Amemoryless%20%3D%20range%281,%2013%29%0Aresult1%20%3D%20list%28reversed%28numbers%29%29%0Aresult2%20%3D%20tuple%28reversed%28memoryless%29%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false)).\n", + "\n", + "To reiterate some more new terminology from this chapter, we describe [reversed()](https://docs.python.org/3/library/functions.html#reversed) as *lazy*, whereas [list()](https://docs.python.org/3/library/functions.html#func-list) and [tuple()](https://docs.python.org/3/library/functions.html#func-tuple) are *eager*. The former has no significant side effect in memory, while the latter may require a lot of memory." + ] + }, + { + "cell_type": "code", + "execution_count": 399, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" + ] + }, + "execution_count": 399, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(reversed(numbers))" + ] + }, + { + "cell_type": "code", + "execution_count": 400, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)" + ] + }, + "execution_count": 400, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tuple(reversed(memoryless))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Of course, we can also loop over the returned *iterators* instead.\n", + "\n", + "That works because *iterators* are always *iterables*; in particular, as the previous \"*The for Statement (revisited)*\" sub-section explains, the `for`-loops below call `iter(reversed(numbers))` and `iter(reversed(memoryless))` behind the scenes. However, the *iterators* returned by [iter()](https://docs.python.org/3/library/functions.html#iter) are the *same* as the `reversed(numbers)` and `reversed(memoryless)` iterators passed in! In summary, the `for`-loops below involve many subtleties that together make Python the expressive language it is." + ] + }, + { + "cell_type": "code", + "execution_count": 401, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4 1 10 9 6 2 12 3 5 8 11 7 " + ] + } + ], + "source": [ + "for number in reversed(numbers):\n", + " print(number, end=\" \")" + ] + }, + { + "cell_type": "code", + "execution_count": 402, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12 11 10 9 8 7 6 5 4 3 2 1 " + ] + } + ], + "source": [ + "for element in reversed(memoryless):\n", + " print(element, end=\" \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "As with [sorted()](https://docs.python.org/3/library/functions.html#sorted), the [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in does *not* mutate its argument." + ] + }, + { + "cell_type": "code", + "execution_count": 403, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + "execution_count": 403, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 404, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "range(1, 13)" + ] + }, + "execution_count": 404, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "memoryless" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "To point out the potentially obvious, we compare the results of *sorting* `numbers` in *reverse* order with *reversing* it: These are *different* concepts!" + ] + }, + { + "cell_type": "code", + "execution_count": 405, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + "execution_count": 405, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 406, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" + ] + }, + "execution_count": 406, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sorted(numbers, reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 407, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" + ] + }, + "execution_count": 407, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(reversed(numbers))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Whereas both [sorted()](https://docs.python.org/3/library/functions.html#sorted) and [reversed()](https://docs.python.org/3/library/functions.html#reversed) do *not* mutate their arguments, the *mutable* `list` type comes with two methods, [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) and `reverse()`, that implement the same logic but mutate an object, like `numbers` below, *in place*. To indicate that all changes occur *in place*, the [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) and `reverse()` methods always return `None`, which is not shown." + ] + }, + { + "cell_type": "code", + "execution_count": 408, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]" + ] + }, + "execution_count": 408, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "The `reverse()` method is *eager*, as opposed to the *lazy* [reversed()](https://docs.python.org/3/library/functions.html#reversed) built-in. That means the mutations causes by the `reverse()` method are written into memory right away." + ] + }, + { + "cell_type": "code", + "execution_count": 409, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [], + "source": [ + "numbers.reverse()" + ] + }, + { + "cell_type": "code", + "execution_count": 410, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[4, 1, 10, 9, 6, 2, 12, 3, 5, 8, 11, 7]" + ] + }, + "execution_count": 410, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "*Sorting* `numbers` in *reverse* order below is of course still *different* from simply *reversing* it above." + ] + }, + { + "cell_type": "code", + "execution_count": 411, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "numbers.sort(reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 412, + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" + ] + }, + "execution_count": 412, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 413, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "numbers.sort()" + ] + }, + { + "cell_type": "code", + "execution_count": 414, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]" + ] + }, + "execution_count": 414, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numbers" ] }, { @@ -10684,13 +12176,27 @@ } }, "source": [ - "**Sequences** are an abstract idea that summarizes *four* behaviors an object may or may not exhibit: We describe them as **finite** and **ordered** **containers** that we may **loop over**. Examples are objects of type `list`, `tuple`, but also `str`. Objects that exhibit all behaviors *except* being ordered are referred to as **collections**. The objects inside a sequence are labeled with a unique *index*, an `int` object in the range $0 \\leq \\text{index} < \\lvert \\text{sequence} \\rvert$, and called its **elements**.\n", + "**Sequences** are an *abstract* concept that summarizes *four* behaviors an object may or may not exhibit. Sequences are\n", + "- **finite** and\n", + "- **ordered**\n", + "- **containers** that we may\n", + "- **loop over**.\n", "\n", - "`list` objects are **mutable**. That means we can change the references to other objects it contains, and, in particular, re-assign them. On the contrary, `tuple` objects are like **immutable** lists: We can use them in place of any `list` object as long as we do *not* mutate it.\n", + "Examples are the `list`, `tuple`, but also the `str` types.\n", "\n", - "Often, the work we do with sequences follows the **map-filter-reduce paradigm**: We apply the same transformation to all elements, filter some of them out, and calculate summary statistics from the remaining ones.\n", + "Objects that exhibit all behaviors *except* being ordered are referred to as **collections**.\n", "\n", - "An essential idea in this chapter is that, in many situations, we need *not* work with all the data **materialized** in memory. Instead, **iterators** allow us to process sequential data on a one-by-one basis." + "The objects inside a sequence are called its **elements** and may be labeled with a unique **index**, an `int` object in the range $0 \\leq \\text{index} < \\lvert \\text{sequence} \\rvert$.\n", + "\n", + "`list` objects are **mutable**. That means we can change the references to the other objects it contains, and, in particular, re-assign them.\n", + "\n", + "On the contrary, `tuple` objects are like **immutable** lists: We can use them in place of any `list` object as long as we do *not* need to mutate it. Often, `tuple` objects are also used to model **records** of related **fields**.\n", + "\n", + "The tasks we do with sequential data follow the **map-filter-reduce paradigm**: We apply the same transformation to all elements, filter some of them out, and calculate summary statistics from the remaining ones.\n", + "\n", + "An essential idea in this chapter is that, in many situations, we need *not* have all the data **materialized** in memory. Instead, **iterators** allow us to process sequential data on a one-by-one basis.\n", + "\n", + "Examples for iterators are the `map`, `filter`, and `generator` types." ] } ],