Compare commits
No commits in common. "main" and "v0.0.0" have entirely different histories.
144 changed files with 64124 additions and 69156 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
|
@ -1,3 +1,11 @@
|
||||||
**/.ipynb_checkpoints/
|
# Environments
|
||||||
.python-version
|
.env/
|
||||||
|
env/
|
||||||
.venv/
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Jupyter
|
||||||
|
.ipynb_checkpoints/
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
default_stages: [commit]
|
|
||||||
fail_fast: true
|
|
||||||
repos:
|
|
||||||
- repo: local
|
|
||||||
hooks:
|
|
||||||
- id: doctests
|
|
||||||
name: Run the xdoctests in the source files
|
|
||||||
entry: poetry run nox -s doctests --
|
|
||||||
language: system
|
|
||||||
stages: [commit, merge-commit]
|
|
||||||
types: [python]
|
|
||||||
- id: fix-branch-references
|
|
||||||
name: Check for wrong branch references
|
|
||||||
entry: poetry run nox -s fix-branch-references --
|
|
||||||
language: system
|
|
||||||
stages: [commit, merge-commit]
|
|
||||||
types: [text]
|
|
||||||
# Enable hooks provided by the pre-commit project to
|
|
||||||
# enforce rules that local tools could not that easily.
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
||||||
rev: v3.2.0
|
|
||||||
hooks:
|
|
||||||
- id: check-added-large-files
|
|
||||||
args: [--maxkb=250]
|
|
||||||
- id: check-merge-conflict
|
|
||||||
- id: no-commit-to-branch
|
|
||||||
args: [--branch, main]
|
|
||||||
- id: trailing-whitespace
|
|
||||||
|
|
@ -1,873 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/00_intro/00_content.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# An Introduction to Python and Programming"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"This book is a *thorough* introduction to programming in [Python <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/).\n",
|
|
||||||
"\n",
|
|
||||||
"It teaches the concepts behind and the syntax of the core Python language as defined by the [Python Software Foundation <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/psf/) in the official [language reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/index.html). Furthermore, it introduces commonly used functionalities from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) and popular third-party libraries like [numpy <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.numpy.org/), [pandas <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://pandas.pydata.org/), [matplotlib <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://matplotlib.org/), and others."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "-"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/logo.png\" width=\"15%\" align=\"left\">"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"There are *no* prerequisites for reading this book."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Objective"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The **main goal** of this introduction is to **prepare** the student **for further studies** in the \"field\" of **data science**."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Why data science?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The term **[data science <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Data_science)** is rather vague and does *not* refer to an academic discipline. Instead, the term was popularized by the tech industry, who also coined non-meaningful job titles such as \"[rockstar](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas)\" or \"[ninja developers](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas).\" Most *serious* definitions describe the field as being **multi-disciplinary** *integrating* scientific methods, algorithms, and systems thinking to extract knowledge from structured and unstructured data, *and* also emphasize the importance of **[domain knowledge <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Domain_knowledge)**.\n",
|
|
||||||
"\n",
|
|
||||||
"Recently, this integration aspect feeds back into the academic world. The [MIT](https://www.mit.edu/), for example, created the new [Stephen A. Schwarzman College of Computing](http://computing.mit.edu) for [artificial intelligence <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Artificial_intelligence) with a 1 billion dollar initial investment where students undergo a \"bilingual\" curriculum with half the classes in quantitative and method-centric fields and the other half in domains such as biology, business, chemistry, politics, (art) history, or linguistics (cf., the [official Q&As](http://computing.mit.edu/faq/) or this [NYT article](https://www.nytimes.com/2018/10/15/technology/mit-college-artificial-intelligence.html)). Their strategists see a future where programming skills are just as naturally embedded into students' curricula as are nowadays subjects like calculus, statistics, or academic writing. Then, programming literacy is not just another \"nice to have\" skill but a prerequisite, or an enabler, to understanding more advanced topics in the actual domains studied."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Installation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"To \"read\" this book in the most meaningful way, a working installation of **Python 3.8** with [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) is needed.\n",
|
|
||||||
"\n",
|
|
||||||
"For a tutorial on how to install Python on your computer, follow the instructions in the [README.md](https://github.com/webartifex/intro-to-python/blob/main/README.md#installation) file in the project's [GitHub repository <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/webartifex/intro-to-python). If you cannot install Python on your own machine, you may open the book interactively in the cloud with [Binder <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Jupyter Notebooks"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The document you are viewing is a so-called [Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html), a file format introduced by the [Jupyter Project](https://jupyter.org/).\n",
|
|
||||||
"\n",
|
|
||||||
"\"Jupyter\" is an [acronym <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Acronym) derived from the names of the three major programming languages **[Julia](https://julialang.org/)**, **[Python <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org)**, and **[R](https://www.r-project.org/)**, all of which play significant roles in the world of data science. The Jupyter Project's idea is to serve as an integrating platform such that different programming languages and software packages can be used together within the same project.\n",
|
|
||||||
"\n",
|
|
||||||
"Jupyter notebooks have become a de-facto standard for communicating and exchanging results in the data science community - both in academia and business - and provide an alternative to command-line interface (CLI or \"terminal\") based ways of running Python code. As an example for the latter case, we could start the default [Python interpreter <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/tutorial/interpreter.html) that comes with every installation by typing the `python` command into a CLI (or `poetry run python` if the project is managed with the [poetry](https://python-poetry.org/docs/) CLI tool as explained in the [README.md](https://github.com/webartifex/intro-to-python/blob/main/README.md#alternative-installation-for-instructors) file). Then, as the screenshot below shows, we could execute Python code like `1 + 2` or `print(\"Hello World\")` line by line simply by typing it following the `>>>` **prompt** and pressing the **Enter** key. For an introductory course, however, this would be rather tedious and probably scare off many beginners."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/cli_example.png\" width=\"50%\">"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"One reason for the popularity of Jupyter notebooks is that they allow mixing text with code in the same document. Text may be formatted with the [Markdown <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://guides.github.com/features/mastering-markdown/) language and mathematical formulas typeset with [LaTeX](https://www.overleaf.com/learn/latex/Free_online_introduction_to_LaTeX_%28part_1%29). Moreover, we may include pictures, plots, and even videos. Because of these features, the notebooks developed for this book come in a self-contained \"tutorial\" style enabling students to simply read them from top to bottom while executing the code snippets.\n",
|
|
||||||
"\n",
|
|
||||||
"Other ways of running Python code are to use the [IPython <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://ipython.org/) CLI tool instead of the default interpreter or a full-fledged [Integrated Development Environment <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Integrated_development_environment) (e.g., the commercial [PyCharm](https://www.jetbrains.com/pycharm/) or the free [Spyder <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/spyder-ide/spyder) that comes with the Anaconda Distribution)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Markdown Cells vs. Code Cells"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A Jupyter notebook consists of cells that have a type associated with them. So far, only cells of type \"Markdown\" have been used, which is the default way to present formatted text.\n",
|
|
||||||
"\n",
|
|
||||||
"The cells below are examples of \"Code\" cells containing actual Python code: They calculate the sum of `1` and `2` and print out `\"Hello World\"` when executed, respectively. To edit an existing code cell, enter into it with a mouse click. You are \"in\" a code cell if its frame is highlighted in blue. We call that the **edit mode**.\n",
|
|
||||||
"\n",
|
|
||||||
"There is also a **command mode** that you reach by hitting the **Escape** key. That un-highlights the frame. You are now \"out\" of but still \"on\" the cell. If you were already in command mode, hitting the Escape key does *nothing*.\n",
|
|
||||||
"\n",
|
|
||||||
"Using the **Enter** and **Escape** keys, you can now switch between the two modes.\n",
|
|
||||||
"\n",
|
|
||||||
"To **execute**, or \"run,\" a code cell, hold down the **Control** key and press **Enter**. Note how you do *not* go to the subsequent cell if you keep re-executing the cell you are on. Alternatively, you can hold the **Shift** key and press **Enter**, which executes a cell *and* places your focus on the subsequent cell or creates a new one if there is none."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"3"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"1 + 2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Hello World\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"print(\"Hello World\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Similarly, a Markdown cell is also in either edit or command mode. For example, double-click on the text you are reading: This puts you into edit mode. Now, you could change the formatting (e.g., print a word in *italics* or **bold**) and \"execute\" the cell to render the text as specified.\n",
|
|
||||||
"\n",
|
|
||||||
"To change a cell's type, choose either \"Code\" or \"Markdown\" in the navigation bar at the top. Alternatively, you can press either the **Y** or **M** key in command mode.\n",
|
|
||||||
"\n",
|
|
||||||
"Sometimes, a code cell starts with an exclamation mark `!`. Then, the Jupyter notebook behaves as if the following command were typed directly into a terminal. The cell below asks the `python` CLI to show its version number and is *not* Python code but a command in the [Shell <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Shell_%28computing%29) language. The `!` is useful to execute short CLI commands without leaving a Jupyter notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Python 3.12.2\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"!python --version"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Programming vs. Computer Science vs. IT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"In this book, **programming** is defined as\n",
|
|
||||||
"- a *structured* way of *problem-solving*\n",
|
|
||||||
"- by *expressing* the steps of a *computation* or *process*\n",
|
|
||||||
"- and thereby *documenting* the process in a formal way.\n",
|
|
||||||
"\n",
|
|
||||||
"Programming is always *concrete* and based on a *particular case*. It exhibits elements of an *art* or a *craft* as we hear programmers call code \"beautiful\" or \"ugly\" or talk about the \"expressive\" power of an application."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"That is different from **computer science**, which is\n",
|
|
||||||
"- a field of study comparable to applied *mathematics* that\n",
|
|
||||||
"- asks *abstract* questions (e.g., \"Is something computable at all?\"),\n",
|
|
||||||
"- develops and analyses *algorithms* and *data structures*,\n",
|
|
||||||
"- and *proves* the *correctness* of a program.\n",
|
|
||||||
"\n",
|
|
||||||
"In a sense, a computer scientist does not need to know a programming language to work, and many computer scientists only know how to produce \"ugly\" looking code in the eyes of professional programmers."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**IT** or **information technology** is a term that has many meanings to different people. Often, it has something to do with hardware or physical devices, both of which are out of scope for programmers and computer scientists. Sometimes, it refers to a [support function](https://en.wikipedia.org/wiki/Value_chain#Support_activities) within a company. Many computer scientists and programmers are more than happy if their printer and internet connection work as they often do not know a lot more about that than \"non-technical\" people."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Why Python?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### What is Python?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Here is a brief history of and some background on Python (cf., also this [TechRepublic article](https://www.techrepublic.com/article/python-is-eating-the-world-how-one-developers-side-project-became-the-hottest-programming-language-on-the-planet/) for a more elaborate story):\n",
|
|
||||||
"\n",
|
|
||||||
"- [Guido van Rossum <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Guido_van_Rossum) (Python’s **[Benevolent Dictator for Life <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life)**) was bored during a week around Christmas 1989 and started Python as a hobby project \"that would keep \\[him\\] occupied\" for some days\n",
|
|
||||||
"- the idea was to create a **general-purpose** scripting **language** that would allow fast *prototyping* and would *run on every operating system*\n",
|
|
||||||
"- Python grew through the 90s as van Rossum promoted it via his \"Computer Programming for Everybody\" initiative that had the *goal to encourage a basic level of coding literacy* as an equal knowledge alongside English literacy and math skills\n",
|
|
||||||
"- to become more independent from its creator, the next major version **Python 2** - released in 2000 and still in heavy use as of today - was **open-source** from the get-go which attracted a *large and global community of programmers* that *contributed* their expertise and best practices in their free time to make Python even better\n",
|
|
||||||
"- **Python 3** resulted from a significant overhaul of the language in 2008 taking into account the *learnings from almost two decades*, streamlining the language, and getting ready for the age of **big data**\n",
|
|
||||||
"- the language is named after the sketch comedy group [Monty Python <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Monty_Python)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"#### Summary"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Python is a **general-purpose** programming **language** that allows for *fast development*, is *easy to read*, **open-source**, long-established, unifies the knowledge of *hundreds of thousands of experts* around the world, runs on basically every machine, and can handle the complexities of applications involving **big data**."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Why open-source?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Couldn't a company like Google, Facebook, or Microsoft come up with a better programming language? The following is an argument on why this can likely not be the case.\n",
|
|
||||||
"\n",
|
|
||||||
"Wouldn't it be weird if professors and scholars of English literature and language studies dictated how we'd have to speak in day-to-day casual conversations or how authors of poesy and novels should use language constructs to achieve a particular type of mood? If you agree with that premise, it makes sense to assume that even programming languages should evolve in a \"natural\" way as users *use* the language over time and in *new* and *unpredictable* contexts creating new conventions."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Loose *communities* are the primary building block around which open-source software projects are built. Someone - like Guido - starts a project and makes it free to use for anybody (e.g., on a code-sharing platform like [GitHub <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/)). People find it useful enough to solve one of their daily problems and start using it. They see how a project could be improved and provide new use cases (e.g., via the popularized concept of a [pull request <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://help.github.com/articles/about-pull-requests/)). The project grows both in lines of code and people using it. After a while, people start local user groups to share their same interests and meet regularly (e.g., this is a big market for companies like [Meetup](https://www.meetup.com/) or non-profits like [PyData <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://pydata.org/)). Out of these local and usually monthly meetups grow yearly conferences on the country or even continental level (e.g., the original [PyCon <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://us.pycon.org/) in the US, [EuroPython <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://europython.eu/), or [PyCon.DE <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://de.pycon.org/)). The content presented at these conferences is made publicly available via GitHub and YouTube (e.g., [PyCon 2019 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.youtube.com/channel/UCxs2IIVXaEHHA4BtTiWZ2mQ) or [EuroPython <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](http://europython.tv/)) and serves as references on what people are working on and introductions to the endless number of specialized fields."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"While these communities are somewhat loose and continuously changing, smaller in-groups, often democratically organized and elected (e.g., the [Python Software Foundation <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/psf/)), take care of, for example, the development of the \"core\" Python language itself.\n",
|
|
||||||
"\n",
|
|
||||||
"Python itself is just a specification (i.e., a set of rules) as to what is allowed and what not: It must first be implemented (c.f., next section below). The current version of Python can always be looked up in the [Python Language Reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/index.html). To make changes to that, anyone can make a so-called **[Python Enhancement Proposal <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/dev/peps/)**, or **PEP** for short, where it needs to be specified what exact changes are to be made and argued why that is a good thing to do. These PEPs are reviewed by the [core developers <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://devguide.python.org/coredev/) and interested people and are then either accepted, modified, or rejected if, for example, the change introduces internal inconsistencies. This process is similar to the **double-blind peer review** established in academia, just a lot more transparent. Many of the contributors even held or hold positions in academia, one more indicator of the high quality standards in the Python community. To learn more about PEPs, check out [PEP 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/dev/peps/pep-0001/) that describes the entire process.\n",
|
|
||||||
"\n",
|
|
||||||
"In total, no one single entity can control how the language evolves, and the users' needs and ideas always feed back to the language specification via a quality controlled and \"democratic\" process."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Besides being **free** as in \"free beer,\" a major benefit of open-source is that one can always *look up how something works in detail*: That is the literal meaning of *open* source and a difference to commercial languages (e.g., [MATLAB](https://www.mathworks.com/products/matlab.html)) as a programmer can always continue to *study best practices* or find out how things are implemented. Along this way, many *errors are uncovered*, as well. Furthermore, if one runs an open-source application, one can be reasonably sure that no bad people built in a \"backdoor.\" [Free software <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Free_software) is consequently free of charge but brings *many other freedoms* with it, most notably the freedom to change the code."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Isn't C a lot faster?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The default Python implementation is written in the C language and called CPython. This is also what the Anaconda Distribution uses.\n",
|
|
||||||
"\n",
|
|
||||||
"[C <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/C_%28programming_language%29) and [C++ <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/C%2B%2B) (cf., this [introduction](https://www.learncpp.com/)) are wide-spread and long-established (i.e., since the 1970s) programming languages employed in many mission-critical software systems (e.g., operating systems themselves, low latency databases and web servers, nuclear reactor control systems, airplanes, ...). They are fast, mainly because the programmer not only needs to come up with the **business logic** but also manage the computer's memory.\n",
|
|
||||||
"\n",
|
|
||||||
"In contrast, Python automatically manages the memory for the programmer. So, speed here is a trade-off between application run time and engineering/development time. Often, the program's run time is not that important: For example, what if C needs 0.001 seconds in a case where Python needs 0.1 seconds to do the same thing? When the requirements change and computing speed becomes an issue, the Python community offers many third-party libraries - usually also written in C - where specific problems can be solved in near-C time."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"#### Summary"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"While it is true that a language like C is a lot faster than Python when it comes to *pure* **computation time**, this does not matter in many cases as the *significantly shorter* **development cycles** are the more significant cost factor in a rapidly changing world."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Who uses it?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "-"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/example_python_users.png\" width=\"70%\">"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"While ad-hominem arguments are usually not the best kind of reasoning, we briefly look at some examples of who uses Python and leave it up to the reader to decide if this is convincing or not:\n",
|
|
||||||
"\n",
|
|
||||||
"- **[Massachusetts Institute of Technology](https://www.mit.edu/)**\n",
|
|
||||||
" - teaches Python in its [introductory course](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/) to computer science independent of the student's major\n",
|
|
||||||
" - replaced the infamous course on the [Scheme](https://groups.csail.mit.edu/mac/projects/scheme/) language (cf., [source <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_hn.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_so.png\">](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 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",
|
|
||||||
" - 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",
|
|
||||||
"- **[Facebook](https://facebook.com/)** uses Python besides C++ and its legacy PHP (a language for building websites; the \"cool kid\" from the early 2000s)\n",
|
|
||||||
"- **[Instagram](https://instagram.com/)** operates the largest installation of the popular **web framework [Django](https://www.djangoproject.com/)** (cf., [source](https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366))\n",
|
|
||||||
"- **[Spotify](https://spotify.com/)** bases its data science on Python (cf., [source](https://labs.spotify.com/2013/03/20/how-we-use-python-at-spotify/))\n",
|
|
||||||
"- **[Netflix](https://netflix.com/)** also runs its predictive models on Python (cf., [source](https://medium.com/netflix-techblog/python-at-netflix-86b6028b3b3e))\n",
|
|
||||||
"- **[Dropbox](https://dropbox.com/)** \"stole\" Guido van Rossom from Google to help scale the platform (cf., [source](https://medium.com/dropbox-makers/guido-van-rossum-on-finding-his-way-e018e8b5f6b1))\n",
|
|
||||||
"- **[JPMorgan Chase](https://www.jpmorganchase.com/)** requires new employees to learn Python as part of the onboarding process starting with the 2018 intake (cf., [source](https://www.ft.com/content/4c17d6ce-c8b2-11e8-ba8f-ee390057b8c9?segmentId=a7371401-027d-d8bf-8a7f-2a746e767d56))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_so.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_so.png\">](https://stackoverflow.blog/2017/09/14/python-growing-quickly/) and [DataCamp](https://www.datacamp.com/community/blog/python-scientific-computing-case)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/growth_of_major_programming_languages.png\" width=\"50%\">"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"As the graph below shows, neither Google's very own language **[Go](https://golang.org/)** nor **[R](https://www.r-project.org/)**, a domain-specific language in the niche of statistics, can compete with Python's year-to-year growth."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/growth_of_smaller_programming_languages.png\" width=\"50%\">"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"[IEEE Sprectrum](https://spectrum.ieee.org/computing/software/the-top-programming-languages-2019) provides a more recent comparison of programming language's popularity. Even news and media outlets notice the recent popularity of Python: [Economist](https://www.economist.com/graphic-detail/2018/07/26/python-is-becoming-the-worlds-most-popular-coding-language), [Huffington Post](https://www.huffingtonpost.com/entry/why-python-is-the-best-programming-language-with-which_us_59ef8f62e4b04809c05011b9), [TechRepublic](https://www.techrepublic.com/article/why-python-is-so-popular-with-developers-3-reasons-the-language-has-exploded/), and [QZ](https://qz.com/1408660/the-rise-of-python-as-seen-through-a-decade-of-stack-overflow/)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## How to learn Programming"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### ABC Rule"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**A**lways **b**e **c**oding.\n",
|
|
||||||
"\n",
|
|
||||||
"Programming is more than just writing code into a text file. It means reading through parts of the [documentation <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/), blogs with best practices, and tutorials, or researching problems on [Stack Overflow <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_so.png\">](https://stackoverflow.com/) while trying to implement features in the application at hand. Also, it means using command-line tools to automate some part of the work or manage different versions of a program, for example, with **[git](https://git-scm.com/)**. In short, programming involves a lot of \"muscle memory,\" which can only be built and kept up through near-daily usage.\n",
|
|
||||||
"\n",
|
|
||||||
"Further, many aspects of software architecture and best practices can only be understood after having implemented some requirements for the very first time. Coding also means \"breaking\" things to find out what makes them work in the first place.\n",
|
|
||||||
"\n",
|
|
||||||
"Therefore, coding is learned best by just doing it for some time on a daily or at least a regular basis and not right before some task is due, just like learning a \"real\" language."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### The Maker's Schedule"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"[Y Combinator <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_hn.png\">](https://www.ycombinator.com/) co-founder [Paul Graham <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Paul_Graham_%28programmer%29) wrote a very popular and often cited [article](http://www.paulgraham.com/makersschedule.html) where he divides every person into belonging to one of two groups:\n",
|
|
||||||
"\n",
|
|
||||||
"- **Managers**: People that need to organize things and command others (e.g., a \"boss\" or manager). Their schedule is usually organized by the hour or even 30-minute intervals.\n",
|
|
||||||
"- **Makers**: People that create things (e.g., 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",
|
|
||||||
"\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."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Phase Iteration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"When being asked the above question, most programmers answer something that can be classified into one of two broader groups.\n",
|
|
||||||
"\n",
|
|
||||||
"**1) Toy Problem, Case Study, or Prototype**: Pick some problem, break it down into smaller sub-problems, and solve them with an end in mind.\n",
|
|
||||||
"\n",
|
|
||||||
"**2) Books, Video Tutorials, and Courses**: Research the best book, blog, video, or tutorial for something and work it through from start to end.\n",
|
|
||||||
"\n",
|
|
||||||
"The truth is that you need to iterate between these two phases.\n",
|
|
||||||
"\n",
|
|
||||||
"Building a prototype always reveals issues no book or tutorial can think of before. Data is never as clean as it should be. An algorithm from a textbook must be adapted to a peculiar aspect of a case study. It is essential to learn to \"ship a product\" because only then will one have looked at all the aspects.\n",
|
|
||||||
"\n",
|
|
||||||
"The major downside of this approach is that one likely learns bad \"patterns\" overfitted to the case at hand, and one does not get the big picture or mental concepts behind a solution. This gap can be filled in by well-written books: For example, check the Python/programming books offered by [Packt](https://www.packtpub.com/packt/offers/free-learning/) or [O’Reilly](https://www.oreilly.com/)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Contents"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Part A: Expressing Logic**\n",
|
|
||||||
"\n",
|
|
||||||
"- What is a programming language? What kind of words exist?\n",
|
|
||||||
" - *Chapter 1*: [Elements of a Program <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 2*: [Functions & Modularization <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb)\n",
|
|
||||||
"- What is the flow of execution? How can we form sentences from words?\n",
|
|
||||||
" - *Chapter 3*: [Conditionals & Exceptions <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 4*: [Recursion & Looping <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/00_content.ipynb)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Part B: Managing Data and Memory**\n",
|
|
||||||
"\n",
|
|
||||||
"- How is data stored in memory?\n",
|
|
||||||
" - *Chapter 5*: [Numbers & Bits <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 6*: [Text & Bytes <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 7*: [Sequential Data <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 8*: [Map, Filter, & Reduce <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 9*: [Mappings & Sets <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb)\n",
|
|
||||||
" - *Chapter 10*: Arrays & Dataframes\n",
|
|
||||||
"- How can we create custom data types?\n",
|
|
||||||
" - *Chapter 11*: [Classes & Instances <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## xkcd Comic"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"As with every good book, there has to be a [xkcd](https://xkcd.com/353/) comic somewhere."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import antigravity"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"<img src=\"static/xkcd.png\" width=\"30%\">"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
1052
00_intro_00_content.ipynb
Normal file
1052
00_intro_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 0: Introduction (Review Questions)"
|
"# Chapter 0: Introduction"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read [Chapter 0 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/00_intro/00_content.ipynb).\n",
|
"## Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 0 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -55,7 +62,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: In what sense are **open-source** communities democracies? How are they near-perfect [meritocracies <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Meritocracy)? How is open-source software development similar to academia?"
|
"**Q3**: In what sense are **open-source** communities democracies? How are they near-perfect [meritocracies <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Meritocracy)? How is open-source software development similar to academia?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +90,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -194,7 +201,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,28 +4,35 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/00_intro/02_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/00_intro_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 0: Introduction (Coding Exercises)"
|
"# Chapter 0: Introduction"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read [Chapter 0 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/00_intro/00_content.ipynb)."
|
"## \"Coding\" Exercises"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Mastering Markdown"
|
"The exercises below assume that you have read [Chapter 0 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_introduction_00_content.ipynb) in the book."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Mastering Markdown"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -67,7 +74,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: Integrate the image of the delicious dessert milk rice at this [URL](https://i.ytimg.com/vi/-BoSRlzy9c4/maxresdefault.jpg) into this notebook."
|
"**Q3**: Integrate this image (https://i.ytimg.com/vi/-BoSRlzy9c4/maxresdefault.jpg) of the delicious dessert **milk rice** into this notebook."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -94,7 +101,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,172 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/01_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 1: Elements of a Program (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb) of Chapter 1.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Printing Output"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: *Concatenate* `greeting` and `audience` below with the `+` operator and print out the resulting message `\"Hello World\"` with only *one* call of the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You may have to \"add\" a space character in between `greeting` and `audience`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"greeting = \"Hello\"\n",
|
|
||||||
"audience = \"World\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: How is your answer to **Q1** an example of the concept of **operator overloading**?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: Read the documentation on the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function! How can you print the above message *without* concatenating `greeting` and `audience` first in *one* call of [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print)?\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: The `*objects` in the documentation implies that we can put several *expressions* (i.e., variables) separated by commas within the same call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: What does the `sep=\" \"` mean in the documentation on the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function? Adjust and use it to print out the three names referenced by `first`, `second`, and `third` on *one* line separated by *commas* with only *one* call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"first = \"Anthony\"\n",
|
|
||||||
"second = \"Berta\"\n",
|
|
||||||
"third = \"Christian\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Adjust and use it within the `for`-loop to print the numbers `1` through `10` on *one* line with only *one* call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/02_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 1: Elements of a Program (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb) of Chapter 1.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Simple `for`-loops"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`for`-loops are extremely versatile in Python. That is different from many other programming languages.\n",
|
|
||||||
"\n",
|
|
||||||
"As shown in the first example in [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: Fill in the *condition* of the `if` statement such that only numbers divisible by `3` are printed! Adjust the call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function such that the `for`-loop prints out all the numbers on *one* line of output!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" if ...:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Instead of looping over an *existing* object referenced by a variable like `numbers`, we may also create a *new* object within the `for` statement and loop over it directly. For example, below we write out the `list` object as a *literal*.\n",
|
|
||||||
"\n",
|
|
||||||
"Generically, the objects contained in a `list` objects are referred to as its **elements**. We reflect that in the name of the *target* variable `element` that is assigned a different number in every iteration of the `for`-loop. While we could use *any* syntactically valid name, it is best to choose one that makes sense in the context (e.g., `number` in `numbers`).\n",
|
|
||||||
"\n",
|
|
||||||
"**Q2**: Fill in the condition of the `if` statement such that only numbers consisting of *one* digit are printed out! As before, print out all the numbers on *one* line of output!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for element in [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]:\n",
|
|
||||||
" if ...:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"An easy way to loop over a `list` object in a sorted manner, is to wrap it with the built-in [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) function.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q3**: Fill in the condition of the `if` statement such that only odd numbers are printed out! Put all the numbers on *one* line of output!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in sorted(numbers):\n",
|
|
||||||
" if ...:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Whenever we want to loop over numbers representing a [series <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Series_%28mathematics%29) in the mathematical sense (i.e., a rule to calculate the next number from its predecessor), we may be able to use the [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in.\n",
|
|
||||||
"\n",
|
|
||||||
"For example, to loop over the whole numbers from `0` to `9` (both including) in order, we could write them out in a `list` like below.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q4**: Fill in the call to the [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function such that all the numbers are printed on *one* line ouf output!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: Read the documentation on the [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in! It may be used with either one, two, or three expressions \"passed\" in. What do `start`, `stop`, and `step` mean? Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) to mimic the output of **Q4**!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in range(...):\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q6**: Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out *all* numbers from `1` to `10` (both including)!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in range(...):\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q7**: Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out the *even* numbers from `1` to `10` (both including)! Do *not* use an `if` statement to accomplish this!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in range(...):\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,212 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/04_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 1: Elements of a Program (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [second part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/03_content.ipynb) Chapter 1.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Python as a Calculator"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The [volume of a sphere <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Sphere) is defined as $\\frac{4}{3} * \\pi * r^3$.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q1**: Calculate it for `r = 2.88` and approximate $\\pi$ with `pi = 3.14`!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"pi = 3.14\n",
|
|
||||||
"r = 2.88"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"While Python may be used as a calculator, it behaves a bit differently compared to calculator apps that phones or computers come with and that we are accustomed to.\n",
|
|
||||||
"\n",
|
|
||||||
"A major difference is that Python \"forgets\" intermediate results that are not assigned to variables. On the contrary, the calculators we work with outside of programming always keep the last result and allow us to use it as the first input for the next calculation.\n",
|
|
||||||
"\n",
|
|
||||||
"One way to keep on working with intermediate results in Python is to write the entire calculation as just *one* big expression that is composed of many sub-expressions representing the individual steps in our overall calculation.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q2.1**: Given `a` and `b` like below, subtract the smaller `a` from the larger `b`, divide the difference by `9`, and raise the result to the power of `2`! Use operators that preserve the `int` type of the final result! The entire calculations *must* be placed within *one* code cell.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You may need to group sub-expressions with parentheses `(` and `)`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"a = 42\n",
|
|
||||||
"b = 87"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The code cell below contains nothing but a single underscore `_`. In both, a Python command-line prompt and Jupyter notebooks, the variable `_` is automatically updated and always references the object to which the *last* expression executed evaluated to.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q2.2**: Execute the code cell below! It should evaluate to the *same* result as the previous code cell (i.e., your answer to **Q2.1** assuming you go through this notebook in order)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"_"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2.3**: Implement the same overall calculation as in your answer to **Q2.1** in several independent steps (i.e., code cells)! Use only *one* operator per code cell!\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You should need *two* more code cells after the `b - a` one immediately below. If you *need* to use parentheses, you must be doing something wrong."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"b - a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"_ ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"_ ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3.1**: When answering the questions above, you should have used only **expressions** in the code cells. What are expressions syntactically?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3.2**: The code cells that provide the numbers to work with contain **statements** that are *not* expressions. What are statements? How are they different from expressions?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 1: Elements of a Program (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We end each chapter with a summary of the main points (i.e., **TL;DR** = \"too long; didn't read\"). The essence in this first chapter is that just as a sentence in a real language like English may be decomposed into its parts (e.g., subject, predicate, and objects), the same may be done with programming languages.\n",
|
|
||||||
"\n",
|
|
||||||
"- program\n",
|
|
||||||
" - **sequence** of **instructions** that specify how to perform a computation (= a \"recipe\")\n",
|
|
||||||
" - a \"black box\" that processes **inputs** and transforms them into meaningful **outputs** in a *deterministic* way\n",
|
|
||||||
" - conceptually similar to a mathematical function $f$ that maps some input $x$ to an output $y = f(x)$\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- input (examples)\n",
|
|
||||||
" - data from a CSV file\n",
|
|
||||||
" - text entered on a command line\n",
|
|
||||||
" - data obtained from a database\n",
|
|
||||||
" - etc.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- output (examples)\n",
|
|
||||||
" - result of a computation (e.g., statistical summary of a sample dataset)\n",
|
|
||||||
" - a \"side effect\" (e.g., a transformation of raw input data into cleaned data)\n",
|
|
||||||
" - a physical \"behavior\" (e.g., a robot moving or a document printed)\n",
|
|
||||||
" - etc.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- objects\n",
|
|
||||||
" - distinct and well-contained areas/parts of the memory that hold the actual data\n",
|
|
||||||
" - the concept by which Python manages the memory for us\n",
|
|
||||||
" - can be classified into objects of the same **type** (i.e., same abstract \"structure\" but different concrete data)\n",
|
|
||||||
" - built-in objects (incl. **literals**) vs. user-defined objects (cf., [Chapter 11 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb))\n",
|
|
||||||
" - e.g., `1`, `1.0`, and `\"one\"` are three different objects of distinct types that are also literals (i.e., by the way we type them into the command line Python knows what the value and type are)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- variables\n",
|
|
||||||
" - storage of intermediate **state**\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",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- expressions\n",
|
|
||||||
" - **combinations** of **variables** (incl. **literals**) and **operators**\n",
|
|
||||||
" - do *not* change the involved objects/state of the program\n",
|
|
||||||
" - evaluate to a **value** (i.e., the \"result\" of the expression, usually a new object)\n",
|
|
||||||
" - e.g., `x + 2` evaluates to the (new) object `3` and `1 - 1.0` to `0.0`\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- statements\n",
|
|
||||||
" - instructions that **\"do\" something** and **have side effects** in memory\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 reference an object\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- comments\n",
|
|
||||||
" - **prose** supporting a **human's understanding** of the program\n",
|
|
||||||
" - ignored by Python\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- functions (cf., [Chapter 2 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb))\n",
|
|
||||||
" - named sequences of instructions\n",
|
|
||||||
" - the smaller parts in a larger program\n",
|
|
||||||
" - make a program more modular and thus easier to understand\n",
|
|
||||||
" - include [built-in functions <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html) like [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print), [sum() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sum), or [len() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#len)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"- flow control (cf., [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb) and [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/00_content.ipynb))\n",
|
|
||||||
" - expression of **business logic** or an **algorithm**\n",
|
|
||||||
" - conditional execution of parts of a program (e.g., `if` statements)\n",
|
|
||||||
" - repetitive execution of parts of a program (e.g., `for`-loops)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "303.333px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
3936
01_elements_00_content.ipynb
Normal file
3936
01_elements_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 1: Elements of a Program (Review Questions)"
|
"# Chapter 1: Elements of a Program"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb) and the [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/03_content.ipynb) part of Chapter 1.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +90,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q5**: What are the basic **naming conventions** for variables? What happens if a name collides with one of Python's [keywords <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/lexical_analysis.html#keywords)?"
|
"**Q5**: What are the basic **naming conventions** for variables? What happens if a name collides with one of Python's [keywords <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/reference/lexical_analysis.html#keywords)?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -97,7 +104,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q6**: Advocates of the [functional programming <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Functional_programming) paradigm suggest not to use **mutable** data types in a program. What are the advantages of that approach? What might be a downside?"
|
"**Q6**: Advocates of the [functional programming <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Functional_programming) paradigm suggest not to use **mutable** data types in a program. What are the advantages of that approach? What might be a downside?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -111,7 +118,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -167,7 +174,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q10**: [PEP 8 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/dev/peps/pep-0008/) suggests that developers use **8 spaces** per level of indentation."
|
"**Q10**: [PEP 8 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://www.python.org/dev/peps/pep-0008/) suggests that developers use **8 spaces** per level of indentation."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -194,7 +201,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
473
01_elements_02_exercises.ipynb
Normal file
473
01_elements_02_exercises.ipynb
Normal file
|
|
@ -0,0 +1,473 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/01_elements_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Chapter 1: Elements of a Program"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) in the book.\n",
|
||||||
|
"\n",
|
||||||
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Printing Output"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.1**: *Concatenate* `greeting` and `audience` below with the `+` operator and print out the resulting message `\"Hello World\"` with only *one* call of the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: You may have to \"add\" a space character in between `greeting` and `audience`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"greeting = \"Hello\"\n",
|
||||||
|
"audience = \"World\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.2**: How is your answer to **Q1.1** an example of the concept of **operator overloading**?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.3**: Read the documentation on the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function! How can you print the above message *without* concatenating `greeting` and `audience` first in *one* call of [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print)?\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: The `*objects` in the documentation implies that we can put several *expressions* (i.e., variables) separated by commas within the same call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.4**: When using a function, we may only put **expressions** between the parentheses `(` and `)`. What are expressions syntactically?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.5**: What does the `sep=\" \"` mean in the documentation on the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function? Adjust and use it to print out the three names referenced by `first`, `second`, and `third` on *one* line separated by *commas* with only *one* call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"first = \"Anthony\"\n",
|
||||||
|
"second = \"Berta\"\n",
|
||||||
|
"third = \"Christian\""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.6**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Adjust and use it within the `for`-loop to print the numbers `1` through `10` on *one* line with only *one* call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Python as a Calculator"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The [volume of a sphere <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Sphere) is defined as $\\frac{4}{3} * \\pi * r^3$.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q2.1**: Calculate it for `r = 2.88` and approximate $\\pi$ with `pi = 3.14`!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"pi = 3.14\n",
|
||||||
|
"r = 2.88"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"While Python may be used as a calculator, it behaves a bit differently compared to calculator apps that phones or computers come with and that we are accustomed to.\n",
|
||||||
|
"\n",
|
||||||
|
"A major difference is that Python \"forgets\" intermediate results that are not assigned to variables. On the contrary, the calculators we work with outside of programming always keep the last result and allow us to use it as the first input for the next calculation.\n",
|
||||||
|
"\n",
|
||||||
|
"One way to keep on working with intermediate results in Python is to write the entire calculation as just *one* big expression that is composed of many sub-expressions representing the individual steps in our overall calculation.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q2.2.1**: Given `a` and `b` like below, subtract the smaller `a` from the larger `b`, divide the difference by `9`, and raise the result to the power of `2`! Use operators that preserve the `int` type of the final result! The entire calculations *must* be placed within *one* code cell.\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: You may need to group sub-expressions with parentheses `(` and `)`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"a = 42\n",
|
||||||
|
"b = 87"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The code cell below contains nothing but a single underscore `_`. In both, a Python command-line prompt and Jupyter notebooks, the variable `_` is automatically updated and always references the object to which the *last* expression executed evaluated to.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q2.2.2**: Execute the code cell below! It should evaluate to the *same* result as the previous code cell (i.e., your answer to **Q2.2.1** assuming you go through this notebook in order)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"_"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.2.3**: Implement the same overall calculation as in your answer to **Q2.2.1** in several independent steps (i.e., code cells)! Use only *one* operator per code cell!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: You should need *two* more code cells after the `b - a` one immediately below. If you *need* to use parentheses, you must be doing something wrong."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"b - a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"_ ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"_ ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Simple `for`-loops"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"`for`-loops are extremely versatile in Python. That is different from many other programming languages.\n",
|
||||||
|
"\n",
|
||||||
|
"As shown in the first example in [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List), we can create a `list` like `numbers` and loop over the numbers in it on a one-by-one basis."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q3.1**: Fill in the *condition* of the `if` statement such that only numbers divisible by `3` are printed! Adjust the call of the [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function such that the `for`-loop prints out all the numbers on *one* line of output!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in numbers:\n",
|
||||||
|
" if ...:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Instead of looping over an *existing* object referenced by a variable like `numbers`, we may also create a *new* object within the `for` statement and loop over it directly. For example, below we write out the `list` object as a *literal*.\n",
|
||||||
|
"\n",
|
||||||
|
"Generically, the objects contained in a `list` objects are referred to as its **elements**. We reflect that in the name of the *target* variable `element` that is assigned a different number in every iteration of the `for`-loop. While we could use *any* syntactically valid name, it is best to choose one that makes sense in the context (e.g., `number` in `numbers`).\n",
|
||||||
|
"\n",
|
||||||
|
"**Q3.2**: Fill in the condition of the `if` statement such that only numbers consisting of *one* digit are printed out! As before, print out all the numbers on *one* line of output!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for element in [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]:\n",
|
||||||
|
" if ...:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"An easy way to loop over a `list` object in a sorted manner, is to wrap it with the built-in [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) function.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q3.3**: Fill in the condition of the `if` statement such that only odd numbers are printed out! Put all the numbers on *one* line of output!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in sorted(numbers):\n",
|
||||||
|
" if ...:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Whenever we want to loop over numbers representing a [series <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Series_%28mathematics%29) in the mathematical sense (i.e., a rule to calculate the next number from its predecessor), we may be able to use the [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in.\n",
|
||||||
|
"\n",
|
||||||
|
"For example, to loop over the whole numbers from `0` to `9` (both including) in order, we could write them out in a `list` like below.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q3.4**: Fill in the call to the [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function such that all the numbers are printed on *one* line ouf output!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q3.5**: Read the documentation on the [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in! It may be used with either one, two, or three expressions \"passed\" in. What do `start`, `stop`, and `step` mean? Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) to mimic the output of **Q3.4**!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in range(...):\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q3.6**: Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out *all* numbers from `1` to `10` (both including)!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in range(...):\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q3.7**: Fill in the calls to [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) and [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out the *even* numbers from `1` to `10` (both including)! Do *not* use an `if` statement to accomplish this!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in range(...):\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.7.4"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"base_numbering": 1,
|
||||||
|
"nav_menu": {},
|
||||||
|
"number_sections": false,
|
||||||
|
"sideBar": true,
|
||||||
|
"skip_h1_title": true,
|
||||||
|
"title_cell": "Table of Contents",
|
||||||
|
"title_sidebar": "Contents",
|
||||||
|
"toc_cell": false,
|
||||||
|
"toc_position": {},
|
||||||
|
"toc_section_display": false,
|
||||||
|
"toc_window_display": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 4
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,90 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 2: Functions & Modularization (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A user-defined **function** is a **named sequence** of statements that perform a computation.\n",
|
|
||||||
"\n",
|
|
||||||
"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 code base), and\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",
|
|
||||||
"They may process **parameterized** inputs, **passed** in as **arguments**, and output a **return value**.\n",
|
|
||||||
"\n",
|
|
||||||
"Arguments may be passed in by **position** or **keyword**. Some functions may even require **keyword-only** arguments.\n",
|
|
||||||
"\n",
|
|
||||||
"**Lambda expressions** create anonymous functions.\n",
|
|
||||||
"\n",
|
|
||||||
"Functions are a special kind of **callables**. Any object that may be **called** with the call operator `()` is a callable. Built-in functions and **constructors** are other kinds of callables.\n",
|
|
||||||
"\n",
|
|
||||||
"Core Python can be extended with code from either the **standard library** or **third-party** libraries.\n",
|
|
||||||
"\n",
|
|
||||||
"Outside Jupyter notebooks, Python code is put into **modules** that are grouped in **packages**."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
4673
02_functions_00_content.ipynb
Normal file
4673
02_functions_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 2: Functions & Modularization (Review Questions)"
|
"# Chapter 2: Functions & Modularization"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb) and the [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/02_content.ipynb) part of Chapter 2.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 2 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -125,7 +132,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -181,7 +188,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q11**: The [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) is a collection of numerical tools often used in scientific computing, for example, advanced mathematical functions or utilities for simulation."
|
"**Q11**: The [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) is a collection of numerical tools often used in scientific computing, for example, advanced mathematical functions or utilities for simulation."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -208,7 +215,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,21 +4,28 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/02_functions/01_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/02_functions_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 2: Functions & Modularization (Coding Exercises)"
|
"# Chapter 2: Functions & Modularization"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb) of Chapter 2.\n",
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 2 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -27,18 +34,14 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Volume of a Sphere"
|
"### Volume of a Sphere"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q1**: The [volume of a sphere <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Sphere) is defined as $\\frac{4}{3} * \\pi * r^3$. Calculate this value for $r=10.0$ and round it to 10 digits after the comma.\n",
|
"**Q1**: The [volume of a sphere <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Sphere) is defined as $\\frac{4}{3} * \\pi * r^3$. Calculate this value for $r=10.0$ and round it to 10 digits after the comma. Use the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) to obtain a good approximation of $\\pi$."
|
||||||
"\n",
|
|
||||||
"Hints:\n",
|
|
||||||
"- use an appropriate approximation for $\\pi$\n",
|
|
||||||
"- you may use the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) to do so if you have already looked at the [second part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/02_content.ipynb) of Chapter 2."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -47,7 +50,16 @@
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"import ... # you may drop this cell and use your own approximation for Pi"
|
"import ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"r = ..."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -165,9 +177,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q5**: Using the [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in, write a `for`-loop and calculate the volume of a sphere with `radius = 42.0` for all `digits` from `1` through `20`. Print out each volume on a separate line.\n",
|
"**Q5**: Using the [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in, write a `for`-loop and calculate the volume of a sphere with `radius = 42.0` for all `digits` from `1` through `20`. Print out each volume on a separate line.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Note: This is the first task where you need to use the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) function."
|
"Note: This is the first task where you need to use the built-in [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) function."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -220,7 +232,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/03_conditionals/01_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 3: Conditionals & Exceptions (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb).\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Discounting Customer Orders"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: Write a function `discounted_price()` that takes the positional arguments `unit_price` (of type `float`) and `quantity` (of type `int`) and implements a discount scheme for a line item in a customer order as follows:\n",
|
|
||||||
"\n",
|
|
||||||
"- if the unit price is over 100 dollars, grant 10% relative discount\n",
|
|
||||||
"- if a customer orders more than 10 items, one in every five items is for free\n",
|
|
||||||
"\n",
|
|
||||||
"Only one of the two discounts is granted, whichever is better for the customer.\n",
|
|
||||||
"\n",
|
|
||||||
"The function should then return the overall price for the line item. Do not forget to round appropriately."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def discounted_price(unit_price, quantity):\n",
|
|
||||||
" \"\"\"Calculate the price of a line item in an order.\n",
|
|
||||||
"\n",
|
|
||||||
" Args:\n",
|
|
||||||
" unit_price (float): price of one ordered item\n",
|
|
||||||
" quantity (int): number of items ordered\n",
|
|
||||||
"\n",
|
|
||||||
" Returns:\n",
|
|
||||||
" line_item_price (float)\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Calculate the final price for the following line items of an order:\n",
|
|
||||||
"- $7$ smartphones @ $99.00$ USD\n",
|
|
||||||
"- $3$ workstations @ $999.00$ USD\n",
|
|
||||||
"- $19$ GPUs @ $879.95$ USD\n",
|
|
||||||
"- $14$ Raspberry Pis @ $35.00$ USD"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: Calculate the last two line items with order quantities of $20$ and $15$. What do you observe?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"discounted_price(...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: Looking at the `if`-`else`-logic in the function, why do you think the four example line items in **Q2** were chosen as they were?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/03_conditionals/02_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 3: Conditionals & Exceptions (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb).\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Fizz Buzz"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The kids game [Fizz Buzz <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Fizz_buzz) is said to be often used in job interviews for entry-level positions. However, opinions vary as to how good of a test it is (cf., [source <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_hn.png\">](https://news.ycombinator.com/item?id=16446774)).\n",
|
|
||||||
"\n",
|
|
||||||
"In its simplest form, a group of people starts counting upwards in an alternating fashion. Whenever a number is divisible by $3$, the person must say \"Fizz\" instead of the number. The same holds for numbers divisible by $5$ when the person must say \"Buzz.\" If a number is divisible by both numbers, one must say \"FizzBuzz.\" Probably, this game would also make a good drinking game with the \"right\" beverages."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: First, create a list `numbers` with the numbers from 1 through 100. You could type all numbers manually, but there is, of course, a smarter way. The built-in [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) may be useful here. Read how it works in the documentation. To make the output of [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) a `list` object, you have to wrap it with the [list() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-list) built-in (i.e., `list(range(...))`)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"numbers = ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Loop over the `numbers` list and *replace* numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n",
|
|
||||||
"\n",
|
|
||||||
"In [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/03_content.ipynb#Who-am-I?-And-how-many?), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n",
|
|
||||||
"\n",
|
|
||||||
"So in each iteration of the `for`-loop, you have to determine an `index` variable as well as check the actual `number` for its divisors.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: the order of the conditions is important!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: Create a loop that prints out either the number or any of the Fizz Buzz substitutes in `numbers`! Do it in such a way that the output is concise!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(...)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 3: Conditionals & Exceptions (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"- **boolean expressions** evaluate to either `True` or `False`\n",
|
|
||||||
"- **relational operators** (e.g., `==` or `!=`) compare operands according to \"human\" interpretations\n",
|
|
||||||
"- **logical operators** (e.g., `and` )combine boolean sub-expressions to more \"complex\" expressions\n",
|
|
||||||
"- the **conditional statement** (i.e., the `if` statement) allows **controlling** the **flow of execution** depending on some **conditions**\n",
|
|
||||||
"- a **conditional expression** is a short form of a conditional statement\n",
|
|
||||||
"- **exception handling** is also a common way of **controlling** the **flow of execution**, in particular, if we have to be prepared for bad input data"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 3: Conditionals & Exceptions (Review Questions)"
|
"# Chapter 3: Conditionals & Exceptions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb).\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -123,7 +130,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -180,7 +187,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
291
03_conditionals_02_exercises.ipynb
Normal file
291
03_conditionals_02_exercises.ipynb
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/03_conditionals_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Chapter 3: Conditionals & Exceptions"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb) in the book.\n",
|
||||||
|
"\n",
|
||||||
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Discounting Customer Orders"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.1**: Write a function `discounted_price()` that takes the positional arguments `unit_price` (of type `float`) and `quantity` (of type `int`) and implements a discount scheme for a line item in a customer order as follows:\n",
|
||||||
|
"\n",
|
||||||
|
"- if the unit price is over 100 dollars, grant 10% relative discount\n",
|
||||||
|
"- if a customer orders more than 10 items, one in every five items is for free\n",
|
||||||
|
"\n",
|
||||||
|
"Only one of the two discounts is granted, whichever is better for the customer.\n",
|
||||||
|
"\n",
|
||||||
|
"The function should then return the overall price for the line item. Do not forget to round appropriately."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def discounted_price(unit_price, quantity):\n",
|
||||||
|
" \"\"\"Calculate the price of a line item in an order.\n",
|
||||||
|
"\n",
|
||||||
|
" Args:\n",
|
||||||
|
" unit_price (float): price of one ordered item\n",
|
||||||
|
" quantity (int): number of items ordered\n",
|
||||||
|
"\n",
|
||||||
|
" Returns:\n",
|
||||||
|
" line_item_price (float)\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.2**: Calculate the final price for the following line items of an order:\n",
|
||||||
|
"- $7$ smartphones @ $99.00$ USD\n",
|
||||||
|
"- $3$ workstations @ $999.00$ USD\n",
|
||||||
|
"- $19$ GPUs @ $879.95$ USD\n",
|
||||||
|
"- $14$ Raspberry Pis @ $35.00$ USD"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.3**: Calculate the last two line items with order quantities of $20$ and $15$. What do you observe?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.4**: Looking at the `if`-`else`-logic in the function, why do you think the four example line items in **Q1.2** were chosen as they were?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Fizz Buzz"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The kids game [Fizz Buzz <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Fizz_buzz) is said to be often used in job interviews for entry-level positions. However, opinions vary as to how good of a test it is (cf., [source <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_hn.png\">](https://news.ycombinator.com/item?id=16446774)).\n",
|
||||||
|
"\n",
|
||||||
|
"In its simplest form, a group of people starts counting upwards in an alternating fashion. Whenever a number is divisible by $3$, the person must say \"Fizz\" instead of the number. The same holds for numbers divisible by $5$ when the person must say \"Buzz.\" If a number is divisible by both numbers, one must say \"FizzBuzz.\" Probably, this game would also make a good drinking game with the \"right\" beverages."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.1**: First, create a list `numbers` with the numbers from 1 through 100. You could type all numbers manually, but there is, of course, a smarter way. The built-in [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) may be useful here. Read how it works in the documentation. To make the output of [range() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) a `list` object, you have to wrap it with the [list() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-list) built-in (i.e., `list(range(...))`)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"numbers = ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.2**: Loop over the `numbers` list and *replace* numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n",
|
||||||
|
"\n",
|
||||||
|
"In [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n",
|
||||||
|
"\n",
|
||||||
|
"So in each iteration of the `for`-loop, you have to determine an `index` variable as well as check the actual `number` for its divisors.\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: the order of the conditions is important!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in numbers:\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.3**: Create a loop that prints out either the number or any of the Fizz Buzz substitutes. Do it in such a way that we do not end up with 100 lines of output here."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"for number in numbers:\n",
|
||||||
|
" print(...)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.7.4"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"base_numbering": 1,
|
||||||
|
"nav_menu": {},
|
||||||
|
"number_sections": false,
|
||||||
|
"sideBar": true,
|
||||||
|
"skip_h1_title": true,
|
||||||
|
"title_cell": "Table of Contents",
|
||||||
|
"title_sidebar": "Contents",
|
||||||
|
"toc_cell": false,
|
||||||
|
"toc_position": {},
|
||||||
|
"toc_section_display": false,
|
||||||
|
"toc_window_display": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 4
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,991 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/03_content.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 4: Recursion & Looping (continued)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"While what we learned about the `for` and `while` statements in the [second part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.ipynb) of this chapter suffices to translate any iterative algorithm into code, both come with some syntactic sugar to make life easier for the developer. This last part of the chapter shows how we can further customize the looping logic and introduces as \"trick\" for situations where we cannot come up with a stopping criterion in a `while`-loop."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Stopping Loops prematurely"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"This section introduces additional syntax to customize `for` and `while` statements in our code even further. They are mostly syntactic sugar in that they do not change how a program runs but make its code more readable. We illustrate them for the `for` statement only. However, everything presented in this section also works for the `while` statement."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Example: Is the square of a number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` greater than `100`?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Let's say we have a list of `numbers` and want to check if the square of at least one of its elements is greater than `100`. So, conceptually, we are asking the question if a list of numbers as a whole satisfies a certain condition."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A first naive implementation could look like this: We loop over *every* element in `numbers` and set an **indicator variable** `is_above`, initialized as `False`, to `True` once we encounter an element satisfying the condition.\n",
|
|
||||||
"\n",
|
|
||||||
"This implementation is *inefficient* as even if the *first* element in `numbers` has a square greater than `100`, we loop until the last element: This could take a long time for a big list.\n",
|
|
||||||
"\n",
|
|
||||||
"Moreover, we must initialize `is_above` *before* the `for`-loop and write an `if`-`else`-logic *after* it to check for the result. The actual business logic is *not* conveyed in a clear way."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 8 5 3 12 2 6 9 10 1 4 => at least one number satisfies the condition\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"is_above = False\n",
|
|
||||||
"\n",
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \") # added for didactical purposes\n",
|
|
||||||
" if number ** 2 > 100:\n",
|
|
||||||
" is_above = True\n",
|
|
||||||
"\n",
|
|
||||||
"if is_above:\n",
|
|
||||||
" print(\"=> at least one number satisfies the condition\")\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"=> no number satisfies the condition\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### The `break` Statement"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Python provides the `break` statement (cf., [reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/simple_stmts.html#the-break-statement)) that lets us stop a loop prematurely at any iteration. It is yet another means of controlling the flow of execution, and we say that we \"break out of a loop.\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 => at least one number satisfies the condition\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"is_above = False\n",
|
|
||||||
"\n",
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \") # added for didactical purposes\n",
|
|
||||||
" if number ** 2 > 100:\n",
|
|
||||||
" is_above = True\n",
|
|
||||||
" break\n",
|
|
||||||
"\n",
|
|
||||||
"if is_above:\n",
|
|
||||||
" print(\"=> at least one number satisfies the condition\")\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"=> no number satisfies the condition\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"This is a computational improvement. However, the code still consists of *three* sections: Some initialization *before* the `for`-loop, the loop itself, and some finalizing logic. We prefer to convey the program's idea in *one* compound statement instead."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### The `else`-clause"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"To express the logic in a prettier way, we add an `else`-clause at the end of the `for`-loop (cf., [reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement)). The `else`-clause is executed *only if* the `for`-loop is *not* stopped with a `break` statement *prematurely* (i.e., *before* reaching the *last* iteration in the loop). The word \"else\" implies a somewhat unintuitive meaning and may have better been named a `then`-clause. In most use cases, however, the `else`-clause logically goes together with some `if` statement in the loop's body.\n",
|
|
||||||
"\n",
|
|
||||||
"Overall, the code's expressive power increases. Not many programming languages support an optional `else`-branching for the `for` and `while` statements, which turns out to be very useful in practice."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 => at least one number satisfies the condition\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \") # added for didactical purposes\n",
|
|
||||||
" if number ** 2 > 100:\n",
|
|
||||||
" is_above = True\n",
|
|
||||||
" break\n",
|
|
||||||
"else:\n",
|
|
||||||
" is_above = False\n",
|
|
||||||
"\n",
|
|
||||||
"if is_above:\n",
|
|
||||||
" print(\"=> at least one number satisfies the condition\")\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"=> no number satisfies the condition\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Lastly, we incorporate the finalizing `if`-`else` logic into the `for`-loop, avoiding the `is_above` variable altogether."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 => at least one number satisfies the condition\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \") # added for didactical purposes\n",
|
|
||||||
" if number ** 2 > 100:\n",
|
|
||||||
" print(\"=> at least one number satisfies the condition\")\n",
|
|
||||||
" break\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"=> no number satisfies the condition\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Of course, if we choose the number an element's square has to pass to be larger, for example, to `200`, we have to loop over all `numbers`. There is *no way* to optimize this **[linear search <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Linear_search)** further."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 8 5 3 12 2 6 9 10 1 4 => no number satisfies the condition\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \") # added for didactical purposes\n",
|
|
||||||
" if number ** 2 > 200:\n",
|
|
||||||
" print(\"=> at least one number satisfies the condition\")\n",
|
|
||||||
" break\n",
|
|
||||||
"else:\n",
|
|
||||||
" print(\"=> no number satisfies the condition\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## A first Glance at the **Map-Filter-Reduce** Paradigm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Often, we process some iterable with numeric data, for example, a list of `numbers` as in this book's introductory example in [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List) or, more realistically, data from a CSV file with many rows and columns.\n",
|
|
||||||
"\n",
|
|
||||||
"Processing numeric data usually comes down to operations that may be grouped into one of the following three categories:\n",
|
|
||||||
"\n",
|
|
||||||
"- **mapping**: transform a number according to some functional relationship $y = f(x)$\n",
|
|
||||||
"- **filtering**: throw away individual numbers (e.g., statistical outliers in a sample)\n",
|
|
||||||
"- **reducing**: collect individual numbers into summary statistics\n",
|
|
||||||
"\n",
|
|
||||||
"We study this **map-filter-reduce** paradigm extensively in [Chapter 8 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb) after introducing more advanced data types that are needed to work with \"big\" data.\n",
|
|
||||||
"\n",
|
|
||||||
"Here, we focus on *filtering out* some numbers in a `for`-loop."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Example: A simple Filter"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Calculate the sum of all even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n",
|
|
||||||
"\n",
|
|
||||||
"- \"*all*\" => **loop** over an iterable\n",
|
|
||||||
"- \"*even*\" => **filter** out the odd numbers\n",
|
|
||||||
"- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n",
|
|
||||||
"- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 7,
|
|
||||||
"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": 8,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"8 -> 65 12 -> 145 2 -> 5 6 -> 37 10 -> 101 4 -> 17 "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"370"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"total = 0\n",
|
|
||||||
"\n",
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" if number % 2 == 0: # only keep even numbers\n",
|
|
||||||
" square = (number ** 2) + 1\n",
|
|
||||||
" print(number, \"->\", square, end=\" \") # added for didactical purposes\n",
|
|
||||||
" total += square\n",
|
|
||||||
"\n",
|
|
||||||
"total"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The above code is easy to read as it involves only two levels of indentation.\n",
|
|
||||||
"\n",
|
|
||||||
"In general, code gets harder to comprehend the more **horizontal space** it occupies. It is commonly considered good practice to grow a program **vertically** rather than horizontally. Code compliant with [PEP 8 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://www.python.org/dev/peps/pep-0008/#maximum-line-length) requires us to use *at most* 79 characters in a line!\n",
|
|
||||||
"\n",
|
|
||||||
"Consider the next example, whose implementation in code already starts to look unbalanced."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Example: Several Filters"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Calculate the sum of every third and even number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` after squaring them and adding `1` to the squares:\n",
|
|
||||||
"\n",
|
|
||||||
"- \"*every*\" => **loop** over an iterable\n",
|
|
||||||
"- \"*third*\" => **filter** out all numbers except every third\n",
|
|
||||||
"- \"*even*\" => **filter** out the odd numbers\n",
|
|
||||||
"- \"*square and add $1$*\" => apply the **map** $y = f(x) = x^2 + 1$\n",
|
|
||||||
"- \"*sum*\" => **reduce** the remaining and mapped numbers to their sum"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"8 -> 65 12 -> 145 4 -> 17 "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"227"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"total = 0\n",
|
|
||||||
"\n",
|
|
||||||
"for i, number in enumerate(numbers, start=1):\n",
|
|
||||||
" if i % 3 == 0: # only keep every third number\n",
|
|
||||||
" if number % 2 == 0: # only keep even numbers\n",
|
|
||||||
" square = (number ** 2) + 1\n",
|
|
||||||
" print(number, \"->\", square, end=\" \") # added for didactical purposes \n",
|
|
||||||
" total += square\n",
|
|
||||||
"\n",
|
|
||||||
"total"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"With already three levels of indentation, less horizontal space is available for the actual code block. Of course, one could flatten the two `if` statements with the logical `and` operator, as shown in [Chapter 3 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb#The-if-Statement). Then, however, we trade off horizontal space against a more \"complex\" `if` logic, and this is *not* a real improvement."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### The `continue` Statement"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A Pythonista would instead make use of the `continue` statement (cf., [reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement)) that causes a loop to jump into the next iteration skipping the rest of the code block.\n",
|
|
||||||
"\n",
|
|
||||||
"The revised code fragment below occupies more vertical space and less horizontal space: A *good* trade-off.\n",
|
|
||||||
"\n",
|
|
||||||
"One caveat is that we need to negate the conditions in the `if` statements. Conceptually, we are now filtering \"out\" and not \"in.\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"8 -> 65 12 -> 145 4 -> 17 "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"227"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"total = 0\n",
|
|
||||||
"\n",
|
|
||||||
"for i, number in enumerate(numbers, start=1):\n",
|
|
||||||
" if i % 3 != 0: # only keep every third number\n",
|
|
||||||
" continue\n",
|
|
||||||
" elif number % 2 != 0: # only keep even numbers\n",
|
|
||||||
" continue\n",
|
|
||||||
"\n",
|
|
||||||
" square = (number ** 2) + 1\n",
|
|
||||||
" print(number, \"->\", square, end=\" \") # added for didactical purposes \n",
|
|
||||||
" total += square\n",
|
|
||||||
"\n",
|
|
||||||
"total"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"This is yet another illustration of why programming is an art. The two preceding code cells do the *same* with *identical* time complexity. However, the latter is arguably easier to read for a human, even more so when the business logic grows beyond two filters."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Indefinite Loops"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Sometimes we find ourselves in situations where we *cannot* know ahead of time how often or until which point in time a code block is to be executed."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Example: Guessing a Coin Toss"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Let's consider a game where we randomly choose a variable to be either \"Heads\" or \"Tails\" and the user of our program has to guess it.\n",
|
|
||||||
"\n",
|
|
||||||
"Python provides the built-in [input() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#input) function that prints a message to the user, called the **prompt**, and reads in what was typed in response as a `str` object. We use it to process a user's \"unreliable\" input to our program (i.e., a user might type in some invalid response). Further, we use the [random() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/random.html#random.random) function in the [random <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/random.html) module to model the coin toss.\n",
|
|
||||||
"\n",
|
|
||||||
"A popular pattern to approach such **indefinite loops** is to go with a `while True` statement, which on its own would cause Python to enter into an infinite loop. Then, once a particular event occurs, we `break` out of the loop.\n",
|
|
||||||
"\n",
|
|
||||||
"Let's look at a first and naive implementation."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import random"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"random.seed(42)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {
|
|
||||||
"code_folding": [],
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdin",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Guess if the coin comes up as heads or tails: heads\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Ooops, it was tails\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdin",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Guess if the coin comes up as heads or tails: heads\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Yes, it was heads\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"while True:\n",
|
|
||||||
" guess = input(\"Guess if the coin comes up as heads or tails: \")\n",
|
|
||||||
"\n",
|
|
||||||
" if random.random() < 0.5:\n",
|
|
||||||
" if guess == \"heads\":\n",
|
|
||||||
" print(\"Yes, it was heads\")\n",
|
|
||||||
" break\n",
|
|
||||||
" else:\n",
|
|
||||||
" print(\"Ooops, it was heads\")\n",
|
|
||||||
" else:\n",
|
|
||||||
" if guess == \"tails\":\n",
|
|
||||||
" print(\"Yes, it was tails\")\n",
|
|
||||||
" break\n",
|
|
||||||
" else:\n",
|
|
||||||
" print(\"Ooops, it was tails\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"This version exhibits two *severe* issues where we should improve on:\n",
|
|
||||||
"\n",
|
|
||||||
"1. If a user enters *anything* other than `\"heads\"` or `\"tails\"`, for example, `\"Heads\"` or `\"Tails\"`, the program keeps running *without* the user knowing about the mistake!\n",
|
|
||||||
"2. The code *intermingles* the coin tossing with the processing of the user's input: Mixing *unrelated* business logic in the *same* code block makes a program harder to read and, more importantly, maintain in the long run."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Example: Guessing a Coin Toss (revisited)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Let's refactor the code and make it *modular*.\n",
|
|
||||||
"\n",
|
|
||||||
"First, we divide the business logic into two functions `get_guess()` and `toss_coin()` that are controlled from within a `while`-loop.\n",
|
|
||||||
"\n",
|
|
||||||
"`get_guess()` not only reads in the user's input but also implements a simple input validation pattern in that the [.strip() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html?highlight=__contains__#str.strip) and [.lower() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html?highlight=__contains__#str.lower) methods remove preceding and trailing whitespace and lower case the input ensuring that the user may spell the input in any possible way (e.g., all upper or lower case). Also, `get_guess()` checks if the user entered one of the two valid options. If so, it returns either `\"heads\"` or `\"tails\"`; if not, it returns `None`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def get_guess():\n",
|
|
||||||
" \"\"\"Process the user's input.\n",
|
|
||||||
" \n",
|
|
||||||
" Returns:\n",
|
|
||||||
" guess (str / NoneType): either \"heads\" or \"tails\"\n",
|
|
||||||
" if the input can be parsed and None otherwise\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" guess = input(\"Guess if the coin comes up as heads or tails: \")\n",
|
|
||||||
" # handle frequent cases of \"misspelled\" user input\n",
|
|
||||||
" guess = guess.strip().lower()\n",
|
|
||||||
"\n",
|
|
||||||
" if guess in [\"heads\", \"tails\"]:\n",
|
|
||||||
" return guess\n",
|
|
||||||
" return None"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"`toss_coin()` models a fair coin toss when called with default arguments."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def toss_coin(p_heads=0.5):\n",
|
|
||||||
" \"\"\"Simulate the tossing of a coin.\n",
|
|
||||||
"\n",
|
|
||||||
" Args:\n",
|
|
||||||
" p_heads (optional, float): probability that the coin comes up \"heads\";\n",
|
|
||||||
" defaults to 0.5 resembling a fair coin\n",
|
|
||||||
"\n",
|
|
||||||
" Returns:\n",
|
|
||||||
" side_on_top (str): \"heads\" or \"tails\"\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" if random.random() < p_heads:\n",
|
|
||||||
" return \"heads\"\n",
|
|
||||||
" return \"tails\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Second, we rewrite the `if`-`else`-logic to handle the case where `get_guess()` returns `None` explicitly: Whenever the user enters something invalid, a warning is shown, and another try is granted. We use the `is` operator and not the `==` operator as `None` is a singleton object.\n",
|
|
||||||
"\n",
|
|
||||||
"The `while`-loop takes on the role of **glue code** that manages how other parts of the program interact with each other."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"random.seed(42)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdin",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Guess if the coin comes up as heads or tails: invalid\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Make sure to enter your guess correctly!\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdin",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Guess if the coin comes up as heads or tails: Heads\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Yes, it was heads\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"while True:\n",
|
|
||||||
" guess = get_guess()\n",
|
|
||||||
" result = toss_coin()\n",
|
|
||||||
"\n",
|
|
||||||
" if guess is None:\n",
|
|
||||||
" print(\"Make sure to enter your guess correctly!\")\n",
|
|
||||||
" elif guess == result:\n",
|
|
||||||
" print(\"Yes, it was\", result)\n",
|
|
||||||
" break\n",
|
|
||||||
" else:\n",
|
|
||||||
" print(\"Ooops, it was\", result)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Now, the program's business logic is expressed in a clearer way. More importantly, we can now change it more easily. For example, we could make the `toss_coin()` function base the tossing on a probability distribution other than the uniform (i.e., replace the [random.random() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/random.html#random.random) function with another one). In general, modular architecture leads to improved software maintenance."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 4: Recursion & Looping (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Iteration** is about **running blocks of code repeatedly**.\n",
|
|
||||||
"\n",
|
|
||||||
"There are two redundant approaches to achieving that.\n",
|
|
||||||
"\n",
|
|
||||||
"First, we combine functions that call themselves with conditional statements. This concept is known as **recursion** and suffices to control the flow of execution in *every* way we desire. For a beginner, this approach of **backward** reasoning might not be intuitive, but it turns out to be a handy tool to have in one's toolbox.\n",
|
|
||||||
"\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\" 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)."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
7158
04_iteration_00_content.ipynb
Normal file
7158
04_iteration_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 4: Recursion & Looping (Review Questions)"
|
"# Chapter 4: Recursion & Looping"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.ipynb), and the [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb) part of Chapter 4.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -111,7 +118,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -247,7 +254,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,21 +4,28 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/01_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 4: Recursion & Looping (Coding Exercises)"
|
"# Chapter 4: Recursion & Looping"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/00_content.ipynb) of Chapter 4.\n",
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read the \"*Recursion*\" part in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) of the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -27,14 +34,14 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Towers of Hanoi"
|
"### Towers of Hanoi"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"A popular example of a problem that is solved by recursion art the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)**.\n",
|
"A popular example of a problem that is solved by recursion art the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)**.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In its basic version, a tower consisting of, for example, four disks with increasing radii, is placed on the left-most of **three** adjacent spots. In the following, we refer to the number of disks as $n$, so here $n = 4$.\n",
|
"In its basic version, a tower consisting of, for example, four disks with increasing radii, is placed on the left-most of **three** adjacent spots. In the following, we refer to the number of disks as $n$, so here $n = 4$.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -43,7 +50,7 @@
|
||||||
"1. Disks can only be moved individually, and\n",
|
"1. Disks can only be moved individually, and\n",
|
||||||
"2. a disk with a larger radius must *never* be placed on a disk with a smaller one.\n",
|
"2. a disk with a larger radius must *never* be placed on a disk with a smaller one.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Although the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** are a **classic** example, introduced by the mathematician [Édouard Lucas <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/%C3%89douard_Lucas) already in 1883, it is still **actively** researched as this scholarly [article](https://www.worldscientific.com/doi/abs/10.1142/S1793830919300017?journalCode=dmaa&) published in January 2019 shows.\n",
|
"Although the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** are a **classic** example, introduced by the mathematician [Édouard Lucas <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/%C3%89douard_Lucas) already in 1883, it is still **actively** researched as this scholarly [article](https://www.worldscientific.com/doi/abs/10.1142/S1793830919300017?journalCode=dmaa&) published in January 2019 shows.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Despite being so easy to formulate, the game is quite hard to solve.\n",
|
"Despite being so easy to formulate, the game is quite hard to solve.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -82,7 +89,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### Video Review Questions"
|
"#### Video Review Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -117,7 +124,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: The **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem is of **exponential growth**. What does that mean? What does that imply for large $n$?"
|
"**Q3**: The **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem is of **exponential growth**. What does that mean? What does that imply for large $n$?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -145,7 +152,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### Naive Translation to Python"
|
"#### Naive Translation to Python"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -266,7 +273,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7**: `sol()` calls itself *two* more times with the correct 2-tuples chosen from the three available spots `origin`, `intermediate`, and `destination`.\n",
|
"**Q7**: `sol()` calls itself *two* more times with the correct 2-tuples chosen from the three available spots `origin`, `intermediate`, and `destination`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"*In between* the two recursive function calls, use [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out from where to where the \"remaining and largest\" disk has to be moved!"
|
"*In between* the two recursive function calls, use [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out from where to where the \"remaining and largest\" disk has to be moved!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -316,7 +323,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### Pythonic Refactoring"
|
"#### Pythonic Refactoring"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -372,7 +379,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"Figure out how the arguments are passed on in the two recursive `hanoi()` calls and finish `hanoi()`.\n",
|
"Figure out how the arguments are passed on in the two recursive `hanoi()` calls and finish `hanoi()`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hint: Do not forget to use [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out the moves!"
|
"Hint: Do not forget to use [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) to print out the moves!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -438,7 +445,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### Passing a Value \"down\" the Recursion Tree"
|
"#### Passing a Value \"down\" the Recursion Tree"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -498,7 +505,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q13**: Complete the two recursive function calls with the same arguments as in `hanoi()`! Do *not* change the already filled in `offset` arguments!\n",
|
"**Q13**: Complete the two recursive function calls with the same arguments as in `hanoi()`! Do *not* change the already filled in `offset` arguments!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Then, adjust the use of [print() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#print) from above to print out the moves with their order number!"
|
"Then, adjust the use of [print() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#print) from above to print out the moves with their order number!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -548,21 +555,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Lastly, it is to be mentioned that for problem instances with a small `n_disks` argument, it is easier to collect all the moves first in a `list` object and then add the order number with the [enumerate() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#enumerate) built-in."
|
"Lastly, it is to be mentioned that for problem instances with a small `n_disks` argument, it is easier to collect all the moves first in a `list` object and then add the order number with the [enumerate() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#enumerate) built-in."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### Open Question"
|
"#### Open Question"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q15**: Conducting your own research on the internet, what can you say about generalizing the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem to a setting with *more than three* landing spots?"
|
"**Q15**: Conducting your own research on the internet, what can you say about generalizing the **[Towers of Hanoi <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Tower_of_Hanoi)** problem to a setting with *more than three* landing spots?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -589,7 +596,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,21 +4,28 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/04_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_03_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 4: Recursion & Looping (Coding Exercises)"
|
"# Chapter 4: Recursion & Looping"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [third part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb) of Chapter 4.\n",
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read the \"*Looping*\" part in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) of the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -27,16 +34,16 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Throwing Dice"
|
"### Throwing the Dice"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In this exercise, you will model the throwing of dice within the context of a guessing game similar to the one shown in the \"*Example: Guessing a Coin Toss*\" section in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb#Example:-Guessing-a-Coin-Toss).\n",
|
"In this exercise, you will model the throwing of dice within the context of a guessing game similar to the one shown in the \"*Example: Guessing a Coin Toss*\" section in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Example:-Guessing-a-Coin-Toss).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"As the game involves randomness, we import the [random <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/random.html) module from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html). To follow best practices, we set the random seed as well."
|
"As the game involves randomness, we import the [random <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/random.html) module from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html). To follow best practices, we set the random seed as well."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -79,7 +86,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q2**: What function from the [random <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/random.html) module that we have seen already is useful for modeling a single throw of the `fair_die`? Write a simple expression (i.e., one function call) that draws one of the equally likely sides! Execute the cell a couple of times to \"see\" the probability distribution!"
|
"**Q2**: What function from the [random <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/random.html) module that we have seen already is useful for modeling a single throw of the `fair_die`? Write a simple expression (i.e., one function call) that draws one of the equally likely sides! Execute the cell a couple of times to \"see\" the probability distribution!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -124,9 +131,9 @@
|
||||||
"source": [
|
"source": [
|
||||||
"`throws` contains the simulation results as absolute counts.\n",
|
"`throws` contains the simulation results as absolute counts.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q4**: Complete the `for`-loop below to convert the counts in `throws` to relative frequencies stored in a `list` called `frequencies`! Round the frequencies to three decimals with the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#round) function!\n",
|
"**Q4**: Complete the `for`-loop below to convert the counts in `throws` to relative frequencies stored in a `list` called `frequencies`! Round the frequencies to three decimals with the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#round) function!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hints: Initialize `frequencies` just as `throws` above. How many iterations does the `for`-loop have? `6` or `100000`? You may want to obtain an `index` variable with the [enumerate() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#enumerate) built-in."
|
"Hints: Initialize `frequencies` just as `throws` above. How many iterations does the `for`-loop have? `6` or `100000`? You may want to obtain an `index` variable with the [enumerate() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#enumerate) built-in."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -206,7 +213,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q8**: The built-in [input() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#input) allows us to ask the user to enter a `guess`. What is the data type of the object returned by [input() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#input)? Assume the user enters the `guess` as a number (i.e., \"1\", \"2\", ...) and not as a text (e.g., \"one\")."
|
"**Q8**: The built-in [input() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#input) allows us to ask the user to enter a `guess`. What is the data type of the object returned by [input() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#input)? Assume the user enters the `guess` as a number (i.e., \"1\", \"2\", ...) and not as a text (e.g., \"one\")."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -382,7 +389,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,85 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 5: Numbers & Bits (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"There exist three numeric types in core Python:\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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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., $\\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 various **abstract** ideas of what numbers are in mathematics."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
8052
05_numbers_00_content.ipynb
Normal file
8052
05_numbers_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 5: Numbers & Bits (Review Questions)"
|
"# Chapter 5: Numbers & Bits"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/01_content.ipynb), and the [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/02_content.ipynb) part of Chapter 5. Some questions regard the [Appendix <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/03_appendix.ipynb); that is indicated with a **\\***.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -62,9 +69,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: Colors are commonly expressed in the **hexadecimal system** in websites (cf., the [HTML <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/HTML) and [CSS <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) formats).\n",
|
"**Q3**: Colors are commonly expressed in the **hexadecimal system** in websites (cf., the [HTML <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/HTML) and [CSS <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) formats).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"For example, $#000000$, $#ff9900$, and $#ffffff$ turn out to be black, orange, and white. The six digits are read in *pairs of two* from left to right, and the *three pairs* correspond to the proportions of red, green, and blue mixed together. They reach from $0_{16} = 0_{10}$ for $0$% to $\\text{ff}_{16} = 255_{10}$ for $100$% (cf., this [article <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/RGB_color_model) for an in-depth discussion).\n",
|
"For example, $#000000$, $#ff9900$, and $#ffffff$ turn out to be black, orange, and white. The six digits are read in *pairs of two* from left to right, and the *three pairs* correspond to the proportions of red, green, and blue mixed together. They reach from $0_{16} = 0_{10}$ for $0$% to $\\text{ff}_{16} = 255_{10}$ for $100$% (cf., this [article <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/RGB_color_model) for an in-depth discussion).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In percent, what are the proportions of red, green, and blue that make up orange? Calculate the three percentages separately! How many **bytes** are needed to encode a color? How many **bits** are that?"
|
"In percent, what are the proportions of red, green, and blue that make up orange? Calculate the three percentages separately! How many **bytes** are needed to encode a color? How many **bits** are that?"
|
||||||
]
|
]
|
||||||
|
|
@ -122,7 +129,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7**: What data type, built-in or from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html), is best suited to represent the [transcendental numbers <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Transcendental_number) $\\pi$ and $\\text{e}$?"
|
"**Q7**: What data type, built-in or from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html), is best suited to represent the [transcendental numbers <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Transcendental_number) $\\pi$ and $\\text{e}$?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -150,7 +157,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -178,7 +185,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q10**: With the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#round) function, we obtain a *precise* representation for any `float` object if we can live with *less than* $15$ digits of precision."
|
"**Q10**: With the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#round) function, we obtain a *precise* representation for any `float` object if we can live with *less than* $15$ digits of precision."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -206,7 +213,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q12**: The [IEEE 754 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/IEEE_754) standard's **special values** provide no benefit in practice as we could always use a **[sentinel <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Sentinel_value)** value (i.e., a \"dummy\"). For example, instead of `nan`, we can always use `0` to indicate a *missing* value."
|
"**Q12**: The [IEEE 754 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/IEEE_754) standard's **special values** provide no benefit in practice as we could always use a **[sentinel <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Sentinel_value)** value (i.e., a \"dummy\"). For example, instead of `nan`, we can always use `0` to indicate a *missing* value."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -251,7 +258,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q15**: From a practitioner's point of view, the built-in [format() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#format) function does the *same* as the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#round) function."
|
"**Q15**: From a practitioner's point of view, the built-in [format() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#format) function does the *same* as the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#round) function."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -265,7 +272,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q16\\***: The `Decimal` type from the [decimal <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/decimal.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) allows us to model the set of the real numbers $\\mathbb{R}$ *precisely*."
|
"**Q16**: The `Decimal` type from the [decimal <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/decimal.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) allows us to model the set of the real numbers $\\mathbb{R}$ *precisely*."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -279,7 +286,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q17\\***: The `Fraction` type from the [fractions <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/fractions.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) allows us to model the set of the rational numbers $\\mathbb{Q}$ *precisely*."
|
"**Q17**: The `Fraction` type from the [fractions <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/fractions.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) allows us to model the set of the rational numbers $\\mathbb{Q}$ *precisely*."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -306,7 +313,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
455
05_numbers_02_exercises.ipynb
Normal file
455
05_numbers_02_exercises.ipynb
Normal file
|
|
@ -0,0 +1,455 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/05_numbers_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Chapter 5: Numbers & Bits"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) in the book.\n",
|
||||||
|
"\n",
|
||||||
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Discounting Customer Orders (revisited)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The \"*Volume of a Sphere*\" problem in [Chapter 2's Exercises <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_02_exercises.ipynb#Volume-of-a-Sphere) section revealed that we must consider the effects of the `float` type's imprecision.\n",
|
||||||
|
"\n",
|
||||||
|
"This becomes even more important when we deal with numeric data modeling accounting or finance data (cf., [this comment <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_so.png\">](https://stackoverflow.com/a/24976426) on \"falsehoods programmers believe about money\").\n",
|
||||||
|
"\n",
|
||||||
|
"In addition to the *inherent imprecision* of numbers in general, the topic of **[rounding numbers <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding)** is also not as trivial as we might expect! [This article](https://realpython.com/python-rounding/) summarizes everything the data science practitioner needs to know.\n",
|
||||||
|
"\n",
|
||||||
|
"In this exercise, we revisit the \"*Discounting Customer Orders*\" problem from [Chapter 3's Exercises <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb#Discounting-Customer-Orders) section and make the `discounted_price()` function work *correctly* for real-life sales data."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1**: Execute the code cells below! What results would you have *expected*, and why?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"round(1.5)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"round(2.5)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"round(2.675, 2)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2**: The built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#round) function implements the \"**[round half to even <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even)**\" strategy. Describe in one or two sentences what that means!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q3**: For the revised `discounted_price()` function, we have to tackle *two* issues: First, we have to replace the built-in `float` type with a data type that allows us to control the precision. Second, the discounted price should be rounded according to a more human-friendly rounding strategy, namely \"**[round half away from zero <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero)**.\"\n",
|
||||||
|
"\n",
|
||||||
|
"Describe in one or two sentences how \"**[round half away from zero <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero)**\" is more in line with how humans think of rounding!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q4**: We use the `Decimal` type from the [decimal <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/decimal.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) to tackle *both* issues simultaneously.\n",
|
||||||
|
"\n",
|
||||||
|
"Assign `euro` a numeric object such that both `Decimal(\"1.5\")` and `Decimal(\"2.5\")` are rounded to `Decimal(\"2\")` (i.e., no decimal) with the [quantize() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize) method!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from decimal import Decimal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"euro = ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Decimal(\"1.5\").quantize(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Decimal(\"2.5\").quantize(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q5**: Obviously, the two preceding code cells still [round half to even <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even).\n",
|
||||||
|
"\n",
|
||||||
|
"The [decimal <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/decimal.html) module defines a `ROUND_HALF_UP` flag that we can pass as the second argument to the [quantize() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize) method. Then, it [rounds half away from zero <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero).\n",
|
||||||
|
"\n",
|
||||||
|
"Add `ROUND_HALF_UP` to the code cells! `Decimal(\"2.5\")` should now be rounded to `Decimal(\"3\")`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from decimal import ROUND_HALF_UP"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Decimal(\"1.5\").quantize(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Decimal(\"2.5\").quantize(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q6**: Instead of `euro`, define `cents` such that rounding occurs to *two* decimals! `Decimal(\"2.675\")` should now be rounded to `Decimal(\"2.68\")`. Do *not* forget to include the `ROUND_HALF_UP` flag!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"cents = ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"Decimal(\"2.675\").quantize(...)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q7**: Rewrite the function `discounted_price()` from [Chapter 3's Exercises <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_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",
|
||||||
|
"- if the unit price is over 100 dollars, grant 10% relative discount\n",
|
||||||
|
"- if a customer orders more than 10 items, one in every five items is for free\n",
|
||||||
|
"\n",
|
||||||
|
"Only one of the two discounts is granted, whichever is better for the customer.\n",
|
||||||
|
"\n",
|
||||||
|
"The function 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 base class** from the [numbers <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/numbers.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) to verify the arguments' types and also that they are both positive!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: It is considered a *best practice* to only round towards the *end* of the calculations."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import numbers"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def discounted_price(unit_price, quantity):\n",
|
||||||
|
" \"\"\"Calculate the price of a line item in an order.\n",
|
||||||
|
"\n",
|
||||||
|
" Args:\n",
|
||||||
|
" unit_price (numbers.Real): price of an ordered item; must be positive\n",
|
||||||
|
" quantity (numbers.Real): number of items ordered; must be positive\n",
|
||||||
|
"\n",
|
||||||
|
" Returns:\n",
|
||||||
|
" line_item_price (decimal.Decimal): precision of 2 decimals\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # Basic input validation.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Calculate the final price if only\n",
|
||||||
|
" # the first discount scheme is applied.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Calculate the final price if only\n",
|
||||||
|
" # the second discount scheme is applied.\n",
|
||||||
|
" # \"One in every five\" means we need to figure out\n",
|
||||||
|
" # how many full groups of five are contained.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Choose the better option for the customer.\n",
|
||||||
|
" ...\n",
|
||||||
|
" # Round correctly for pricing purposes.\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q8**: Execute the code cells below and verify the final price for the following four test cases:\n",
|
||||||
|
"\n",
|
||||||
|
"- $7$ smartphones @ $99.00$ USD\n",
|
||||||
|
"- $3$ workstations @ $999.00$ USD\n",
|
||||||
|
"- $19$ GPUs @ $879.95$ USD\n",
|
||||||
|
"- $14$ Raspberry Pis @ $35.00$ USD\n",
|
||||||
|
"\n",
|
||||||
|
"The output should now *always* be a `Decimal` number with *two* decimals!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(99, 7)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(999, 3)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(879.95, 19)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(35, 14)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"This also works if `quantity` is passed in as a `float` type."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(99, 7.0)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Decimals beyond the first two are gracefully discarded (i.e., *without* rounding errors accumulating)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(99.0001, 7)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The basic input validation ensures that the user of `discounted_price()` does not pass in invalid data. Here, the `\"abc\"` creates a `TypeError`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(\"abc\", 7)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"A `-1` passed in as `unit_price` results in a `ValueError`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"discounted_price(-1, 7)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.7.4"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"base_numbering": 1,
|
||||||
|
"nav_menu": {},
|
||||||
|
"number_sections": false,
|
||||||
|
"sideBar": true,
|
||||||
|
"skip_h1_title": true,
|
||||||
|
"title_cell": "Table of Contents",
|
||||||
|
"title_sidebar": "Contents",
|
||||||
|
"toc_cell": false,
|
||||||
|
"toc_position": {},
|
||||||
|
"toc_section_display": false,
|
||||||
|
"toc_window_display": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 4
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,75 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 6: Text & Bytes (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Textual data is modeled with the **immutable** `str` type.\n",
|
|
||||||
"\n",
|
|
||||||
"The `str` type supports *four* orthogonal **abstract concepts** that together constitute the idea of a **sequence**: Every `str` object is an *iterable container* of a *finite* number of *ordered* characters.\n",
|
|
||||||
"\n",
|
|
||||||
"A single **character** in a `str` object follows the idea of a **Unicode** character. It is mapped to a *unique* **code point** that is encoded into **bytes** with a dedicated character encoding, for example, **UTF-8**."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
6349
06_text_00_content.ipynb
Normal file
6349
06_text_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 6: Text & Bytes (Review Questions)"
|
"# Chapter 6: Text & Bytes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb) and [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/01_content.ipynb) part of Chapter 6.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 6 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -95,7 +102,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -178,7 +185,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,21 +4,28 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/06_text/01_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/06_text_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 6: Text & Bytes (Coding Exercises)"
|
"# Chapter 6: Text & Bytes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb) of Chapter 6.\n",
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 6 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -27,18 +34,18 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Detecting Palindromes"
|
"### Detecting Palindromes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"[Palindromes <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Palindrome) are sequences of characters that read the same backward as forward. Examples are first names like \"Hannah\" or \"Otto,\" words like \"radar\" or \"level,\" or sentences like \"Was it a car or a cat I saw?\"\n",
|
"[Palindromes <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Palindrome) are sequences of characters that read the same backward as forward. Examples are first names like \"Hannah\" or \"Otto,\" words like \"radar\" or \"level,\" or sentences like \"Was it a car or a cat I saw?\"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In this exercise, you implement various functions that check if the given arguments are palindromes or not. We start with an iterative implementation and end with a recursive one.\n",
|
"In this exercise, you implement various functions that check if the given arguments are palindromes or not. We start with an iterative implementation and end with a recursive one.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Conceptually, the first function, `unpythonic_palindrome()`, is similar to the \"*Is the square of a number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` greater than `100`?*\" example in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb#Example:-Is-the-square-of-a-number-in-[7,-11,-8,-5,-3,-12,-2,-6,-9,-10,-1,-4]-greater-than-100?): It assumes that the `text` argument is a palindrome (i.e., it initializes `is_palindrom` to `True`) and then checks in a `for`-loop if a pair of corresponding characters, `forward` and `backward`, contradicts that.\n",
|
"Conceptually, the first function, `unpythonic_palindrome()`, is similar to the \"*Is the square of a number in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` greater than `100`?*\" example in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Example:-Is-the-square-of-a-number-in-[7,-11,-8,-5,-3,-12,-2,-6,-9,-10,-1,-4]-greater-than-100?): It assumes that the `text` argument is a palindrome (i.e., it initializes `is_palindrom` to `True`) and then checks in a `for`-loop if a pair of corresponding characters, `forward` and `backward`, contradicts that.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q1**: How many iterations are needed in the `for`-loop? Take into account that `text` may contain an even or odd number of characters! Inside `unpythonic_palindrome()` below, write an expression whose result is assigned to `chars_to_check`!"
|
"**Q1**: How many iterations are needed in the `for`-loop? Take into account that `text` may contain an even or odd number of characters! Inside `unpythonic_palindrome()` below, write an expression whose result is assigned to `chars_to_check`!"
|
||||||
]
|
]
|
||||||
|
|
@ -221,7 +228,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"**Q5**: Copy your solutions to the previous questions into `almost_pythonic_palindrome()` below!\n",
|
"**Q5**: Copy your solutions to the previous questions into `almost_pythonic_palindrome()` below!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q6**: The [reversed() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#reversed) and [zip() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#zip) built-ins allow us to loop over the same `text` argument *in parallel* in both forward *and* backward order. Finish the `for` statement's header line to do just that!\n",
|
"**Q6**: The [reversed() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#reversed) and [zip() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#zip) built-ins allow us to loop over the same `text` argument *in parallel* in both forward *and* backward order. Finish the `for` statement's header line to do just that!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hint: You may need to slice the `text` argument."
|
"Hint: You may need to slice the `text` argument."
|
||||||
]
|
]
|
||||||
|
|
@ -454,7 +461,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q11**: Copy your code from `pythonic_palindrome()` above into `palindrome_ducks()` below and make the latter conform to *duck typing*!\n",
|
"**Q11**: Copy your code from `pythonic_palindrome()` above into `palindrome_ducks()` below and make the latter conform to *duck typing*!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hints: You may want to use the [str() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-str) built-in. You only need to add *one* short line of code."
|
"Hints: You may want to use the [str() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#func-str) built-in. You only need to add *one* short line of code."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -576,7 +583,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q13**: Implement the final iterative version `is_a_palindrome()` below. Copy your solution from `palindrome_ducks()` above and add code that removes the \"special\" characters (and symbols) from the longer example palindromes above so that they are effectively ignored! Note that this processing should only be done if the `ignore_symbols` argument is set to `True`.\n",
|
"**Q13**: Implement the final iterative version `is_a_palindrome()` below. Copy your solution from `palindrome_ducks()` above and add code that removes the \"special\" characters (and symbols) from the longer example palindromes above so that they are effectively ignored! Note that this processing should only be done if the `ignore_symbols` argument is set to `True`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hints: Use the [replace() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html#str.replace) method on the `str` type to achieve that. You may want to do so within another `for`-loop."
|
"Hints: Use the [replace() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/stdtypes.html#str.replace) method on the `str` type to achieve that. You may want to do so within another `for`-loop."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -974,7 +981,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -1,958 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/00_content.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 7: Sequential Data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We studied numbers (cf., [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/00_content.ipynb)) and textual data (cf., [Chapter 6 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb)) first mainly because objects of the presented data types are \"simple.\" That is so for two reasons: First, they are *immutable*, and, as we saw in the \"*Who am I? And how many?*\" section in [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/03_content.ipynb#Who-am-I?-And-how-many?), mutable objects can quickly become hard to reason about. Second, they are \"flat\" in the sense that they are *not* composed of other objects.\n",
|
|
||||||
"\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, [Chapter 8 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb), [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb), and [Chapter 10 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/10_arrays/00_content.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 (i.e., they provide references to other objects). Unsurprisingly, computer scientists refer to the ideas behind these data types as **[data structures <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Spreadsheet) or [matrices <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Matrix_%28mathematics%29) and [vectors <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29). These 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."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## Collections vs. Sequences"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"[Chapter 6 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb#A-\"String\"-of-Characters) already describes the **sequence** properties of `str` objects. In this section, we take a step back and study these properties one by one.\n",
|
|
||||||
"\n",
|
|
||||||
"The [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/02_content.ipynb#The-Numerical-Tower), where we use the ones from the [numbers <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/numbers.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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",
|
|
||||||
"\n",
|
|
||||||
"As an illustration, consider `numbers` and `text` below, two objects of *different* types."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"numbers = [7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]\n",
|
|
||||||
"text = \"Lorem ipsum dolor sit amet.\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"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."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"7 11 8 5 3 12 2 6 9 10 1 4 "
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in numbers:\n",
|
|
||||||
" print(number, end=\" \")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"L o r e m i p s u m d o l o r s i t a m e t . "
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for character in text:\n",
|
|
||||||
" print(character, end=\" \")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"In [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html) include [enumerate() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#enumerate), [sum() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sum), or [zip() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import collections.abc as abc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"collections.abc.Iterable"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"abc.Iterable"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"As seen in [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/02_content.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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 `text`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Iterable)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 7,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 7,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Iterable)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Contrary to `list` or `str` objects, numeric objects are *not* iterable."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(999, abc.Iterable)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Instead of asking, we could try to loop over `999`, but this results in a `TypeError`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "TypeError",
|
|
||||||
"evalue": "'int' object is not iterable",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
|
||||||
"Cell \u001b[0;32mIn[9], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mdigit\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;241;43m999\u001b[39;49m\u001b[43m:\u001b[49m\n\u001b[1;32m 2\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mprint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdigit\u001b[49m\u001b[43m)\u001b[49m\n",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m: 'int' object is not iterable"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for digit in 999:\n",
|
|
||||||
" print(digit)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Most of the data types in this chapter and [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb) and [Chapter 10 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/10_arrays/00_content.ipynb) exhibit three [orthogonal <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Orthogonality) (i.e., \"independent\") behaviors, formalized by ABCs in the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module as:\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",
|
|
||||||
"The characteristical operation supported by `Container` types is the `in` operator for membership testing."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"0 in numbers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"\"l\" in text"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Alternatively, we could also check if `numbers` and `text` are `Container` types with [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#isinstance)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Container)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Container)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Numeric objects do *not* \"contain\" references to other objects, and that is why they are considered \"flat\" data types. The `in` operator raises a `TypeError`. Conceptually speaking, Python views numeric types as \"wholes\" without any \"parts.\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(999, abc.Container)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "TypeError",
|
|
||||||
"evalue": "argument of type 'int' is not iterable",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
|
||||||
"Cell \u001b[0;32mIn[15], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;241;43m9\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;241;43m999\u001b[39;49m\n",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m: argument of type 'int' is not iterable"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"9 in 999"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Analogously, being `Sized` types, we can pass `numbers` and `text` as the argument to the built-in [len() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Unicode) make up the `str` object. *Abstractly* speaking, both data types exhibit the *same* behavior of *finiteness*."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"12"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"len(numbers)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"27"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"len(text)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 18,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 18,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Sized)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 19,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 19,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Sized)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"On the contrary, even though `999` consists of three digits for humans, numeric objects in Python have no concept of a \"size\" or \"length,\" and the [len() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#len) function raises a `TypeError`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 20,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 20,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(999, abc.Sized)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 21,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "TypeError",
|
|
||||||
"evalue": "object of type 'int' has no len()",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
|
||||||
"Cell \u001b[0;32mIn[21], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mlen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m999\u001b[39;49m\u001b[43m)\u001b[49m\n",
|
|
||||||
"\u001b[0;31mTypeError\u001b[0m: object of type 'int' has no len()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"len(999)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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",
|
|
||||||
"Without going into too much detail, one way to read the summary table at the beginning of the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 22,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 22,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Collection)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 23,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 23,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Collection)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](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",
|
|
||||||
"The [reversed() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#reversed) built-in allows us to loop over the elements or characters in reverse order."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 24,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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": 25,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
". 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(text):\n",
|
|
||||||
" print(character, end=\" \")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 26,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 26,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Reversible)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 27,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 27,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Reversible)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Collections that exhibit this fourth behavior are referred to as **sequences**, formalized with the `Sequence` ABC in the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 28,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 28,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(numbers, abc.Sequence)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 29,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 29,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"isinstance(text, abc.Sequence)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The data types introduced in this chapter are sequences. Nevertheless, we also look at some data types that are neither collections nor sequences but are still useful to model sequential data in practice in [Chapter 8 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb).\n",
|
|
||||||
"\n",
|
|
||||||
"In Python-related documentations, the terms collection and sequence are heavily used, and the data science practitioner should always think of them in terms of the three or four behaviors they exhibit.\n",
|
|
||||||
"\n",
|
|
||||||
"Data types that are collections but not sequences are covered in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb)."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,257 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/02_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 7: Sequential Data (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [second part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/01_content.ipynb) of Chapter 7.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Working with Lists"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: Write a function `nested_sum()` that takes a `list` object as its argument, which contains other `list` objects with numbers, and adds up the numbers! Use `nested_numbers` below to test your function!\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You need at least one `for`-loop."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"nested_numbers = [[1, 2, 3], [4], [5], [6, 7], [8], [9]]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def nested_sum(list_of_lists):\n",
|
|
||||||
" \"\"\"Add up numbers in nested lists.\n",
|
|
||||||
" \n",
|
|
||||||
" Args:\n",
|
|
||||||
" list_of_lists (list): A list containing the lists with the numbers\n",
|
|
||||||
" \n",
|
|
||||||
" Returns:\n",
|
|
||||||
" sum (int or float)\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"nested_sum(nested_numbers)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Generalize `nested_sum()` into a function `mixed_sum()` that can process a \"mixed\" `list` object, which contains numbers and other `list` objects with numbers! Use `mixed_numbers` below for testing!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Use the built-in [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mixed_numbers = [[1, 2, 3], 4, 5, [6, 7], 8, [9]]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import collections.abc as abc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def mixed_sum(list_of_lists_or_numbers):\n",
|
|
||||||
" \"\"\"Add up numbers in nested lists.\n",
|
|
||||||
" \n",
|
|
||||||
" Args:\n",
|
|
||||||
" list_of_lists_or_numbers (list): A list containing both numbers and\n",
|
|
||||||
" lists with numbers\n",
|
|
||||||
" \n",
|
|
||||||
" Returns:\n",
|
|
||||||
" sum (int or float)\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mixed_sum(mixed_numbers)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3.1**: Write a function `cum_sum()` that takes a `list` object with numbers as its argument and returns a *new* `list` object with the **cumulative sums** of these numbers! So, `sum_up` below, `[1, 2, 3, 4, 5]`, should return `[1, 3, 6, 10, 15]`.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: The idea behind is similar to the [cumulative distribution function <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Cumulative_distribution_function) from statistics."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sum_up = [1, 2, 3, 4, 5]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def cum_sum(numbers):\n",
|
|
||||||
" \"\"\"Create the cumulative sums for some numbers.\n",
|
|
||||||
"\n",
|
|
||||||
" Args:\n",
|
|
||||||
" numbers (list): A list with numbers for that the cumulative sums\n",
|
|
||||||
" are calculated\n",
|
|
||||||
" \n",
|
|
||||||
" Returns:\n",
|
|
||||||
" cum_sums (list): A list with all the cumulative sums\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"cum_sum(sum_up)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3.2**: We should always make sure that our functions also work in corner cases. What happens if your implementation of `cum_sum()` is called with an empty list `[]`? Make sure it handles that case *without* crashing! What would be a good return value in this corner case?\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: It is possible to write this without any extra input validation."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"cum_sum([])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,609 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/05_appendix.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 7: Sequential Data (Appendix)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"In the [third part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/03_content.ipynb#Tuples-are-like-\"Immutable-Lists\") of the chapter, we proposed the idea that `tuple` objects are like \"immutable lists.\" Often, however, we use `tuple` objects to represent a **record** of related **fields**. Then, each element has a *semantic* meaning (i.e., a descriptive name).\n",
|
|
||||||
"\n",
|
|
||||||
"As an example, think of a spreadsheet with information on students in a course. Each row represents a record and holds all the data associated with an individual student. The columns (e.g., matriculation number, first name, last name) are the fields that may come as *different* data types (e.g., `int` for the matriculation number, `str` for the names).\n",
|
|
||||||
"\n",
|
|
||||||
"A simple way of modeling a single student is as a `tuple` object, for example, `(123456, \"John\", \"Doe\")`. A disadvantage of this approach is that we must remember the order and meaning of the elements/fields in the `tuple` object.\n",
|
|
||||||
"\n",
|
|
||||||
"An example from a different domain is the representation of $(x, y)$-points in the $x$-$y$-plane. Again, we could use a `tuple` object like `current_position` below to model the point $(4, 2)$."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"current_position = (4, 2)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We implicitly assume that the first element represents the $x$ and the second the $y$ coordinate. While that follows intuitively from convention in math, we should at least add comments somewhere in the code to document this assumption."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## The `namedtuple` Type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A better way is to create a *custom* data type. While that is covered in depth in [Chapter 11 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb), the [collections <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) provides a [namedtuple() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.namedtuple) **factory function** that creates \"simple\" custom data types on top of the standard `tuple` type."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from collections import namedtuple"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"[namedtuple() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.namedtuple) takes two arguments. The first argument is the name of the data type. That could be different from the variable `Point` we use to refer to the new type, but in most cases it is best to keep them in sync. The second argument is a sequence with the field names as `str` objects. The names' order corresponds to the one assumed in `current_position`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"Point = namedtuple(\"Point\", [\"x\", \"y\"])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The `Point` object is a so-called **class**. That is what it means if an object is of type `type`. It can be used as a **factory** to create *new* `tuple`-like objects of type `Point`. In a way, [namedtuple() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.namedtuple) gives us a way to create our own custom **constructors**."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"94457911453856"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"id(Point)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"type(Point)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The value of `Point` is just itself in a *literal notation*."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"__main__.Point"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 6,
|
|
||||||
"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": 7,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"current_position = Point(4, 2)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Now, `current_position` has a somewhat nicer representation. In particular, the coordinates are named `x` and `y`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"Point(x=4, y=2)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"It is *not* a `tuple` any more but an object of type `Point`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"140376178109184"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"id(current_position)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"__main__.Point"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"type(current_position)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We use the dot operator `.` to access the defined attributes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position.x"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position.y"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"As before, we get an `AttributeError` if we try to access an undefined attribute."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "AttributeError",
|
|
||||||
"evalue": "'Point' object has no attribute 'z'",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
||||||
"\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
|
|
||||||
"Cell \u001b[0;32mIn[13], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mcurrent_position\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mz\u001b[49m\n",
|
|
||||||
"\u001b[0;31mAttributeError\u001b[0m: 'Point' object has no attribute 'z'"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position.z"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"`current_position` continues to work like a `tuple` object! That is why we can use `namedtuple` as a replacement for `tuple`. The underlying implementations exhibit the *same* computational efficiencies and memory usages.\n",
|
|
||||||
"\n",
|
|
||||||
"For example, we can index into or loop over `current_position` as it is still a sequence with the familiar four properties."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position[0]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"current_position[1]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"4\n",
|
|
||||||
"2\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in current_position:\n",
|
|
||||||
" print(number)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"2\n",
|
|
||||||
"4\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number in reversed(current_position):\n",
|
|
||||||
" print(number)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 18,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "fragment"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 18,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"len(current_position)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 7: Sequential Data (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**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",
|
|
||||||
"Examples are the `list`, `tuple`, but also the `str` types.\n",
|
|
||||||
"\n",
|
|
||||||
"Objects that exhibit all behaviors *except* being ordered are referred to as **collections**.\n",
|
|
||||||
"\n",
|
|
||||||
"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**."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
6951
07_sequences_00_content.ipynb
Normal file
6951
07_sequences_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 7: Sequential Data (Review Questions)"
|
"# Chapter 7: Sequential Data"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/01_content.ipynb), and the [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/03_content.ipynb) part of Chapter 7. Some questions regard the [Appendix <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/05_appendix.ipynb); that is indicated with a **\\***.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -34,7 +41,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q1**: We have seen **containers** and **iterables** before in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.ipynb#Containers-vs.-Iterables). How do they relate to **sequences**? "
|
"**Q1**: We have seen **containers** and **iterables** before in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables). How do they relate to **sequences**? "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +55,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q2**: What are **abstract base classes**? How can we make use of the ones from the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html)?"
|
"**Q2**: What are **abstract base classes**? How can we make use of the ones from the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html)?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -134,7 +141,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7.2\\***: What do we mean by a **record**? How are `tuple` objects suitable to model records? How can we integrate a **semantic meaning** when working with records into our code?"
|
"**Q7.2**: What do we mean by a **record**? How are `tuple` objects suitable to model records? How can we integrate a **semantic meaning** when working with records into our code?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -162,7 +169,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -176,7 +183,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q9**: `sequence` objects are *not* part of core Python but may be imported from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html)."
|
"**Q9**: `sequence` objects are *not* part of core Python but may be imported from the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html)."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -190,7 +197,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q10**: The built-in [.sort() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html#list.sort) function takes a *finite* **iterable** as its argument an returns a *new* `list` object. On the contrary, the [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) method on `list` objects *mutates* them *in place*."
|
"**Q10**: The built-in [sort() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/stdtypes.html#list.sort) function takes a *finite* **iterable** as its argument an returns a *new* `list` object. On the contrary, the [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) method on `list` objects *mutates* them *in place*."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -231,7 +238,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
|
|
@ -4,21 +4,28 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/04_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/07_sequences_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 7: Sequential Data (Coding Exercises)"
|
"# Chapter 7: Sequential Data"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [third part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/03_content.ipynb) of Chapter 7.\n",
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -27,14 +34,210 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Packing & Unpacking with Functions"
|
"### Working with Lists"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In the \"*Function Definitions & Calls*\" section in [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/03_content.ipynb#Function-Definitions-&-Calls), we define the following function `product()`. In this exercise, you will improve it by making it more \"user-friendly.\""
|
"**Q1.1**: Write a function `nested_sum()` that takes a `list` object as its argument, which contains other `list` objects with numbers, and adds up the numbers! Use `nested_numbers` below to test your function!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: You need at least one `for`-loop."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"nested_numbers = [[1, 2, 3], [4], [5], [6, 7], [8], [9]]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def nested_sum(list_of_lists):\n",
|
||||||
|
" \"\"\"Add up numbers in nested lists.\n",
|
||||||
|
" \n",
|
||||||
|
" Args:\n",
|
||||||
|
" list_of_lists (list): A list containing the lists with the numbers\n",
|
||||||
|
" \n",
|
||||||
|
" Returns:\n",
|
||||||
|
" sum (int or float)\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"nested_sum(nested_numbers)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.2**: Generalize `nested_sum()` into a function `mixed_sum()` that can process a \"mixed\" `list` object, which contains numbers and other `list` objects with numbers! Use `mixed_numbers` below for testing!\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: Use the built-in [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed. Get extra credit for adhering to *goose typing*, as explained in [Chapter 5 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb#Goose-Typing): Use some appropriate abstract base class (ABC) from the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"mixed_numbers = [[1, 2, 3], 4, 5, [6, 7], 8, [9]]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import collections.abc as abc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def mixed_sum(list_of_lists_or_numbers):\n",
|
||||||
|
" \"\"\"Add up numbers in nested lists.\n",
|
||||||
|
" \n",
|
||||||
|
" Args:\n",
|
||||||
|
" list_of_lists_or_numbers (list): A list containing both numbers and\n",
|
||||||
|
" lists with numbers\n",
|
||||||
|
" \n",
|
||||||
|
" Returns:\n",
|
||||||
|
" sum (int or float)\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"mixed_sum(mixed_numbers)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.3.1**: Write a function `cum_sum()` that takes a `list` object with numbers as its argument and returns a *new* `list` object with the **cumulative sums** of these numbers! So, `sum_up` below, `[1, 2, 3, 4, 5]`, should return `[1, 3, 6, 10, 15]`.\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: The idea behind is similar to the [cumulative distribution function <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Cumulative_distribution_function) from statistics."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"sum_up = [1, 2, 3, 4, 5]"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def cum_sum(numbers):\n",
|
||||||
|
" \"\"\"Create the cumulative sums for some numbers.\n",
|
||||||
|
"\n",
|
||||||
|
" Args:\n",
|
||||||
|
" numbers (list): A list with numbers for that the cumulative sums\n",
|
||||||
|
" are calculated\n",
|
||||||
|
" \n",
|
||||||
|
" Returns:\n",
|
||||||
|
" cum_sums (list): A list with all the cumulative sums\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"cum_sum(sum_up)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.3.2**: We should always make sure that our functions also work in corner cases. What happens if your implementation of `cum_sum()` is called with an empty list `[]`? Make sure it handles that case *without* crashing! What would be a good return value in this corner case?\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: It is possible to write this without any extra input validation."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"cum_sum([])"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Packing & Unpacking with Functions"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"In the \"*Function Definitions & Calls*\" section in [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Function-Definitions-&-Calls), we define the following function `product()`. In this exercise, you will improve it by making it more \"user-friendly.\""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +262,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"The `*` in the function's header line *packs* all *positional* arguments passed to `product()` into one *iterable* called `args`.\n",
|
"The `*` in the function's header line *packs* all *positional* arguments passed to `product()` into one *iterable* called `args`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q1**: What is the data type of `args` within the function's body?"
|
"**Q2.1**: What is the data type of `args` within the function's body?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -114,7 +317,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q2**: What line in the body of `product()` causes this exception? What is the exact problem?"
|
"**Q2.2**: What line in the body of `product()` causes this exception? What is the exact problem?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -128,7 +331,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/00_content.ipynb#Function-Definitions-&-Calls), we also pass a `list` object, like `one_hundred`, to `product()`, and *no* exception is raised."
|
"In [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Function-Definitions-&-Calls), we also pass a `list` object, like `one_hundred`, to `product()`, and *no* exception is raised."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -153,7 +356,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: What is wrong with that? What *kind* of error (cf., [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb#Formal-vs.-Natural-Languages)) is that conceptually? Describe precisely what happens to the passed in `one_hundred` in every line within `product()`!"
|
"**Q2.3**: What is wrong with that? What *kind* of error (cf., [Chapter 1 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Formal-vs.-Natural-Languages)) is that conceptually? Describe precisely what happens to the passed in `one_hundred` in every line within `product()`!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -217,7 +420,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q4**: Describe why no error occurs by going over every line in `product()`!"
|
"**Q2.4**: Describe why no error occurs by going over every line in `product()`!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -256,7 +459,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q5**: What line causes troubles now? What is the exact problem?"
|
"**Q2.5**: What line causes troubles now? What is the exact problem?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -270,9 +473,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q6**: Replace the `None` in `product()` above with something reasonable that does *not* cause exceptions! Ensure that `product(42)` and `product(2, 5, 10)` return a correct result.\n",
|
"**Q2.6**: Replace the `None` in `product()` above with something reasonable that does *not* cause exceptions! Ensure that `product(42)` and `product(2, 5, 10)` return a correct result.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hints: It is ok if `product()` returns a result *different* from the `None` above. Look at the documentation of the built-in [sum() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sum) function for some inspiration."
|
"Hints: It is ok if `product()` returns a result *different* from the `None` above. Look at the documentation of the built-in [sum() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#sum) function for some inspiration."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -329,9 +532,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7**: Rewrite `product()` so that it takes a *keyword-only* argument `start`, defaulting to the above *default* or *start* value, and use `start` internally instead of `result`!\n",
|
"**Q2.7**: Rewrite `product()` so that it takes a *keyword-only* argument `start`, defaulting to the above *default* or *start* value, and use `start` internally instead of `result`!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hint: Remember that a *keyword-only* argument is any parameter specified in a function's header line after the first and only `*` (cf., [Chapter 2 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb#Keyword-only-Arguments))."
|
"Hint: Remember that a *keyword-only* argument is any parameter specified in a function's header line after the first (and only) `*` (cf., [Chapter 2 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Keyword-only-Arguments))."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -443,7 +646,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q8**: What is a **collection**? How is that different from a **sequence**?"
|
"**Q2.8**: What is a **collection**? How is that different from a **sequence**?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -457,9 +660,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q9**: Rewrite the latest version of `product()` to check if the *only* positional argument is a *collection* type! If so, its elements are multiplied together. Otherwise, the logic remains the same.\n",
|
"**Q2.9**: Rewrite the latest version of `product()` to check if the *only* positional argument is a *collection* type! If so, its elements are multiplied together. Otherwise, the logic remains the same.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Hints: Use the built-in [len() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#len) and [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#isinstance) functions to check if there is only *one* positional argument and if it is a *collection* type. Use the *abstract base class* `Collection` from the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html). You may want to *re-assign* `args` inside the body."
|
"Hints: Use the built-in [len() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#len) and [isinstance() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#isinstance) functions to check if there is only *one* positional argument and if it is a *collection* type. Use the *abstract base class* `Collection` from the [collections.abc <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/collections.abc.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html). You may want to *re-assign* `args` inside the body."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -544,7 +747,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!"
|
"**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -578,7 +781,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Let's continue to improve `product()` and make it more Pythonic. It is always a good idea to mimic the behavior of built-ins when writing our own functions. And, [sum() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sum), for example, raises a `TypeError` if called *without* any arguments. It does *not* return the \"philosophical\" answer to adding *no* numbers, which would be `0`."
|
"Let's continue to improve `product()` and make it more Pythonic. It is always a good idea to mimic the behavior of built-ins when writing our own functions. And, [sum() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#sum), for example, raises a `TypeError` if called *without* any arguments. It does *not* return the \"philosophical\" answer to adding *no* numbers, which would be `0`."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -594,7 +797,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q10**: Adapt the latest version of `product()` to also raise a `TypeError` if called *without* any *positional* arguments!"
|
"**Q2.10**: Adapt the latest version of `product()` to also raise a `TypeError` if called *without* any *positional* arguments!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -642,7 +845,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,760 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/02_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 8: Map, Filter, & Reduce (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb) and [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/01_content.ipynb) part of Chapter 8.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Removing Outliers in Streaming Data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Let's say we are given a `list` object with random integers like `sample` below, and we want to calculate some basic statistics on them."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample = [\n",
|
|
||||||
" 45, 46, 40, 49, 36, 53, 49, 42, 25, 40, 39, 36, 38, 40, 40, 52, 36, 52, 40, 41,\n",
|
|
||||||
" 35, 29, 48, 43, 42, 30, 29, 33, 55, 33, 38, 50, 39, 56, 52, 28, 37, 56, 45, 37,\n",
|
|
||||||
" 41, 41, 37, 30, 51, 32, 23, 40, 53, 40, 45, 39, 99, 42, 34, 42, 34, 39, 39, 53,\n",
|
|
||||||
" 43, 37, 46, 36, 45, 42, 32, 38, 57, 34, 36, 44, 47, 51, 46, 39, 28, 40, 35, 46,\n",
|
|
||||||
" 41, 51, 41, 23, 46, 40, 40, 51, 50, 32, 47, 36, 38, 29, 32, 53, 34, 43, 39, 41,\n",
|
|
||||||
" 40, 34, 44, 40, 41, 43, 47, 57, 50, 42, 38, 25, 45, 41, 58, 37, 45, 55, 44, 53,\n",
|
|
||||||
" 82, 31, 45, 33, 32, 39, 46, 48, 42, 47, 40, 45, 51, 35, 31, 46, 40, 44, 61, 57,\n",
|
|
||||||
" 40, 36, 35, 55, 40, 56, 36, 35, 86, 36, 51, 40, 54, 50, 49, 36, 41, 37, 48, 41,\n",
|
|
||||||
" 42, 44, 40, 43, 51, 47, 46, 50, 40, 23, 40, 39, 28, 38, 42, 46, 46, 42, 46, 31,\n",
|
|
||||||
" 32, 40, 48, 27, 40, 40, 30, 32, 25, 31, 30, 43, 44, 29, 45, 41, 63, 32, 33, 58,\n",
|
|
||||||
"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"len(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: `list` objects are **sequences**. What *four* behaviors do they always come with?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Write a function `mean()` that calculates the simple arithmetic mean of a given `sequence` with numbers!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: You can solve this task with [built-in functions <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html) only. A `for`-loop is *not* needed."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def mean(sequence):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_mean = mean(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_mean"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: Write a function `std()` that calculates the [standard deviation <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Standard_deviation) of a `sequence` of numbers! Integrate your `mean()` version from before and the [sqrt() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/math.html#math.sqrt) function from the [math <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/math.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) provided to you below. Make sure `std()` calls `mean()` only *once* internally! Repeated calls to `mean()` would be a waste of computational resources.\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Parts of the code are probably too long to fit within the suggested 79 characters per line. So, use *temporary variables* inside your function. Instead of a `for`-loop, you may want to use a `list` comprehension or, even better, a memoryless `generator` expression."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from math import sqrt"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def std(sequence):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_std = std(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_std"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: Complete `standardize()` below that takes a `sequence` of numbers and returns a `list` object with the **[z-scores <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Standard_score)** of these numbers! A z-score is calculated by subtracting the mean and dividing by the standard deviation. Re-use `mean()` and `std()` from before. Again, ensure that `standardize()` calls `mean()` and `std()` only *once*! Further, round all z-scores with the built-in [round() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#round) function and pass on the keyword-only argument `digits` to it.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You may want to use a `list` comprehension instead of a `for`-loop."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def standardize(sequence, *, digits=3):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"z_scores = standardize(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The [pprint() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/pprint.html#pprint.pprint) function from the [pprint <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/pprint.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) allows us to \"pretty print\" long `list` objects compactly."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from pprint import pprint"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"pprint(z_scores, compact=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We know that `standardize()` works correctly if the resulting z-scores' mean and standard deviation approach `0` and `1` for a long enough `sequence`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mean(z_scores), std(z_scores)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Even though `standardize()` calls `mean()` and `std()` only once each, `mean()` is called *twice*! That is so because `std()` internally also re-uses `mean()`!\n",
|
|
||||||
"\n",
|
|
||||||
"**Q5.1**: Rewrite `std()` to take an optional keyword-only argument `seq_mean`, defaulting to `None`. If provided, `seq_mean` is used instead of the result of calling `mean()`. Otherwise, the latter is called.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You must check if `seq_mean` is still the default value."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def std(sequence, *, seq_mean=None):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`std()` continues to work as before."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_std = std(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample_std"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5.2**: Now, rewrite `standardize()` to pass on the return value of `mean()` to `std()`! In summary, `standardize()` calculates the z-scores for the numbers in the `sequence` with as few computational steps as possible."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def standardize(sequence, *, digits=3):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"z_scores = standardize(sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mean(z_scores), std(z_scores)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q6**: With both `sample` and `z_scores` being materialized `list` objects, we can loop over pairs consisting of a number from `sample` and its corresponding z-score. Write a `for`-loop that prints out all the \"outliers,\" as which we define numbers with an absolute z-score above `1.96`. There are *four* of them in the `sample`.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: Use the [abs() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#abs) and [zip() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#zip) built-ins."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We provide a `stream` module with a `data` object that models an *infinite* **stream** of data (cf., the [*stream.py* <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/webartifex/intro-to-python/blob/main/08_mfr/stream.py) file in the repository)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from stream import data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`data` is of type `generator` and has *no* length."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"type(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"len(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"So, the only thing we can do with it is to pass it to the built-in [next() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#next) function and go over the numbers it streams one by one."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q7**: What happens if you call `mean()` with `data` as the argument? What is the problem?\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: If you try it out, you may have to press the \"Stop\" button in the toolbar at the top. Your computer should *not* crash, but you will *have to* restart this Jupyter notebook with \"Kernel\" > \"Restart\" and import `data` again."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mean(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q8**: Write a function `take_sample()` that takes an `iterable` as its argument, like `data`, and creates a *materialized* `list` object out of its first `n` elements, defaulting to `1_000`!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: [next() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#next) and the [range() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-range) built-in may be helpful. You may want to use a `list` comprehension instead of a `for`-loop and write a one-liner. Audacious students may want to look at [isclice() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.islice) in the [itertools <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def take_sample(iterable, *, n=1_000):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We take a `new_sample` from the stream of `data`, and its statistics are similar to the initial `sample`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"new_sample = take_sample(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"len(new_sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"mean(new_sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"std(new_sample)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q9**: Convert `standardize()` into a *new* function `standardized()` that implements the *same* logic but works on a possibly *infinite* stream of data, provided as an `iterable`, instead of a *finite* `sequence`.\n",
|
|
||||||
"\n",
|
|
||||||
"To calculate a z-score, we need the stream's overall mean and standard deviation, and that is *impossible* to calculate if we do not know how long the stream is, and, in particular, if it is *infinite*. So, `standardized()` first takes a sample from the `iterable` internally, and uses the sample's mean and standard deviation to calculate the z-scores.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: `standardized()` *must* return a `generator` object. So, use a `generator` expression as the return value; unless you know about the `yield` statement already (cf., [reference <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement))."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def standardized(iterable, *, digits=3):\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`standardized()` works almost like `standardize()` except that we use it with [next() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#next) to obtain the z-scores one by one."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"z_scores = standardized(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"z_scores"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"type(z_scores)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(z_scores)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q10.1**: `standardized()` allows us to go over an *infinite* stream of z-scores. What we want to do instead is to loop over the stream's raw numbers and skip the outliers. In the remainder of this exercise, you look at the parts that make up the `skip_outliers()` function below to achieve precisely that.\n",
|
|
||||||
"\n",
|
|
||||||
"The first steps in `skip_outliers()` are the same as in `standardized()`: We take a `sample` from the stream of `data` and calculate its statistics."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"sample = ...\n",
|
|
||||||
"seq_mean = ...\n",
|
|
||||||
"seq_std = ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q10.2**: Just as in `standardized()`, write a `generator` expression that produces z-scores one by one! However, instead of just generating a z-score, the resulting `generator` object should produce `tuple` objects consisting of a \"raw\" number from `data` and its z-score.\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: Look at the revisited \"*Averaging Even Numbers*\" example in [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/01_content.ipynb#Example:-Averaging-all-even-Numbers-in-a-List-%28revisited%29) for some inspiration, which also contains a `generator` expression producing `tuple` objects."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"standardizer = (... for ... in data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`standardizer` should produce `tuple` objects."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(standardizer)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q10.3**: Write another `generator` expression that loops over `standardizer`. It contains an `if`-clause that keeps only numbers with an absolute z-score below the `threshold_z`. If you fancy, use `tuple` unpacking."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"threshold_z = 1.96"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"no_outliers = (... for ... in standardizer if ...)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`no_outliers` should produce `int` objects."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(no_outliers)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q10.4**: Lastly, put everything together in the `skip_outliers()` function! Make sure you refer to `iterable` inside the function and not the global `data`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def skip_outliers(iterable, *, threshold_z=1.96):\n",
|
|
||||||
" sample = ...\n",
|
|
||||||
" seq_mean = ...\n",
|
|
||||||
" seq_std = ...\n",
|
|
||||||
" standardizer = ...\n",
|
|
||||||
" no_outliers = ...\n",
|
|
||||||
" return no_outliers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Now, we can create a `generator` object and loop over the `data` in the stream with outliers skipped. Instead of the default `1.96`, we use a `threshold_z` of only `0.05`: That filters out all numbers except `42`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"skipper = skip_outliers(data, threshold_z=0.05)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"skipper"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"type(skipper)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(skipper)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q11**: You implemented the functions `mean()`, `std()`, `standardize()`, `standardized()`, and `skip_outliers()`. Which of them are **eager**, and which are **lazy**? How do these two concepts relate to **finite** and **infinite** data?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,455 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/03_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 8: Map, Filter, & Reduce (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb) and [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/01_content.ipynb) part of Chapter 8.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Packing & Unpacking with Functions (continued)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: Copy your solution to **Q10** from the \"*Packing & Unpacking with Functions*\" exercise in [Chapter 7 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/04_exercises.ipynb) into the code cell below!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import collections.abc as abc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def product(*args, ...):\n",
|
|
||||||
" \"\"\"Multiply all arguments.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Verify that all test cases below work (i.e., the `assert` statements must *not* raise an `AssertionError`)!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"assert product(42) == 42"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"assert product(2, 5, 10) == 100"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"assert product(2, 5, 10, start=2) == 200"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"one_hundred = [2, 5, 10]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"assert product(one_hundred) == 100"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"assert product(*one_hundred) == 100"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: Verify that `product()` raises a `TypeError` when called without any arguments!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"This implementation of `product()` is convenient to use, in particular, because we can pass it any *collection* object with or without *unpacking* it.\n",
|
|
||||||
"\n",
|
|
||||||
"However, `product()` suffers from one last flaw: We cannot pass it a **stream** of data, as modeled, for example, with a `generator` object that produces elements on a one-by-one basis.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q4**: Click through the following code cells and observe what they do!\n",
|
|
||||||
"\n",
|
|
||||||
"The [*stream.py* <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/webartifex/intro-to-python/blob/main/08_mfr/stream.py) module in the book's repository provides a `make_finite_stream()` function. It is a *factory* function creating objects of type `generator` that we use to model *streaming* data."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from stream import make_finite_stream"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"data = make_finite_stream()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"type(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"`generator` objects are good for only *one* thing: Giving us the \"next\" element in a series of possibly *infinitely* many objects. While the `data` object is finite (i.e., execute the next code cell until you see a `StopIteration` exception), ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"next(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"... it has *no* concept of a \"length:\" The built-in [len() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#len) function raises a `TypeError`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"len(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We can use the built-in [list() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-list) constructor to *materialize* all elements. However, in a real-world scenario, these may *not* fit into our machine's memory! If you get an empty `list` object below, you have to create a *new* `data` object above again."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"list(data)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"To be more realistic, `make_finite_stream()` creates `generator` objects producing a varying number of elements."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"list(make_finite_stream())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"list(make_finite_stream())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"list(make_finite_stream())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Let's see what happens if we pass a `generator` object, as created by `make_finite_stream()`, instead of a materialized *collection*, like `one_hundred`, to `product()`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product(make_finite_stream())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: What line causes the `TypeError`? What line is really the problem in `product()`? Hint: These may be different lines. Describe what happens on each line in the function's body until the exception is raised!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q6**: Adapt `product()` one last time to make it work with `generator` objects, or more generallz *iterators*, as well!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: This task is as easy as replacing `Collection` with something else. Which of the three behaviors of *collections* do `generator` objects also exhibit? You may want to look at the documentations on the built-in [max() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#max), [min() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#min), and [sum() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sum) functions: What kind of argument do they take?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def product(*args, ...):\n",
|
|
||||||
" \"\"\"Multiply all arguments.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The final version of `product()` behaves like built-ins in edge cases (i.e., `sum()` also raises a `TypeError` when called without arguments), ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"... works with the arguments passed either separately as *positional* arguments, *packed* together into a single *collection* argument, or *unpacked*, ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product(42)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product(2, 5, 10)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product([2, 5, 10])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product(*[2, 5, 10])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"... and can handle *streaming* data with *indefinite* \"length.\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"product(make_finite_stream())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"In real-world projects, the data science practitioner must decide if it is worthwhile to make a function usable in various different forms as we do in this exercise. This may be over-engineered.\n",
|
|
||||||
"\n",
|
|
||||||
"Yet, two lessons are important to take away:\n",
|
|
||||||
"- It is a good idea to *mimic* the behavior of *built-ins* when accepting arguments, and\n",
|
|
||||||
"- make functions capable of working with *streaming* data."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,75 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 8: Map, Filter, & Reduce (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The operations we do with sequential data commonly 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."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
5312
08_mfr_00_content.ipynb
Normal file
5312
08_mfr_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,22 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 8: Map, Filter, & Reduce (Review Questions)"
|
"\n",
|
||||||
|
"# Chapter 8: Map, Filter, & Reduce"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/01_content.ipynb), and [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/04_content.ipynb) part in Chapter 8.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 8 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,14 +28,14 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q1**: With the [map() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#map) and [filter() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#filter) built-ins and the [reduce() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html), we can replace many tedious `for`-loops and `if` statements. What are some advantages of doing so?"
|
"**Q1**: With the [map() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#map) and [filter() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#filter) built-ins and the [reduce() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html), we can replace many tedious `for`-loops and `if` statements. What are some advantages of doing so?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -41,7 +49,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q2**: Looking at the `lambda` expression inside [reduce() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functools.html#functools.reduce) below, what [built-in function <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html) is mimicked here?"
|
"**Q2**: Looking at the `lambda` expression inside [reduce() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functools.html#functools.reduce) below, what [built-in function <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html) is mimicked here?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -68,7 +76,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q3**: What is the primary use case of **`list` comprehensions**? Why do we describe them as **eager**?"
|
"**Q3**: What is the primary use case of **list comprehensions**? Why do we describe them as **eager**?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -82,7 +90,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q4**: **`generator` expressions** may replace `list` objects and list comprehensions in many scenarios. When evaluated, they create a **lazy** `generator` object that does *not* **materialize** its elements right away. What do we mean by that? What does it mean for a `generator` object to be **exhausted**?"
|
"**Q4**: **Generator expressions** may replace `list` objects and list comprehensions in many scenarios. When evaluated, they create a **lazy** `generator` object that does *not* **materialize** its elements right away. What do we mean by that? What does it mean for a `generator` object to be **exhausted**?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -96,7 +104,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q5**: What does it mean for the **boolean reducers**, the built-in [all() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#all) and [any() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#any) functions, to follow the **short-circuiting** strategy?"
|
"**Q5**: What does it mean for the **boolean reducers**, the built-in [all() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#all) and [any() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#any) functions, to follow the **short-circuiting** strategy?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -124,7 +132,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -152,7 +160,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q8**: Using **`generator` expressions** in place of **`list` comprehensions** wherever possible is a good practice as it makes our programs use memory more efficiently."
|
"**Q8**: Using **generator expressions** in place of **list comprehensions** wherever possible is a good practice as it makes our programs use memory more efficiently."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -166,7 +174,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q9**: Just as **`list` comprehensions** create `list` objects, **`tuple` comprehensions** create `tuple` objects."
|
"**Q9**: Just as **list comprehensions** create `list` objects, **tuple comprehensions** create `tuple` objects."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -193,7 +201,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
1202
08_mfr_02_exercises.ipynb
Normal file
1202
08_mfr_02_exercises.ipynb
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,428 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/01_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 9: Mappings & Sets (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb) of Chapter 9.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Working with Nested Data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Let's write some code to analyze the historic soccer game [Brazil vs. Germany <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Brazil_v_Germany_%282014_FIFA_World_Cup%29) during the 2014 World Cup.\n",
|
|
||||||
"\n",
|
|
||||||
"Below, `players` consists of two nested `dict` objects, one for each team, that hold `tuple` objects (i.e., records) with information on the players. Besides the jersey number, name, and position, each `tuple` objects contains a `list` object with the times when the player scored."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"players = {\n",
|
|
||||||
" \"Brazil\": [\n",
|
|
||||||
" (12, \"Júlio César\", \"Goalkeeper\", []),\n",
|
|
||||||
" (4, \"David Luiz\", \"Defender\", []),\n",
|
|
||||||
" (6, \"Marcelo\", \"Defender\", []),\n",
|
|
||||||
" (13, \"Dante\", \"Defender\", []),\n",
|
|
||||||
" (23, \"Maicon\", \"Defender\", []),\n",
|
|
||||||
" (5, \"Fernandinho\", \"Midfielder\", []),\n",
|
|
||||||
" (7, \"Hulk\", \"Midfielder\", []),\n",
|
|
||||||
" (8, \"Paulinho\", \"Midfielder\", []),\n",
|
|
||||||
" (11, \"Oscar\", \"Midfielder\", [90]),\n",
|
|
||||||
" (16, \"Ramires\", \"Midfielder\", []),\n",
|
|
||||||
" (17, \"Luiz Gustavo\", \"Midfielder\", []),\n",
|
|
||||||
" (19, \"Willian\", \"Midfielder\", []),\n",
|
|
||||||
" (9, \"Fred\", \"Striker\", []),\n",
|
|
||||||
" ],\n",
|
|
||||||
" \"Germany\": [\n",
|
|
||||||
" (1, \"Manuel Neuer\", \"Goalkeeper\", []),\n",
|
|
||||||
" (4, \"Benedikt Höwedes\", \"Defender\", []),\n",
|
|
||||||
" (5, \"Mats Hummels\", \"Defender\", []),\n",
|
|
||||||
" (16, \"Philipp Lahm\", \"Defender\", []),\n",
|
|
||||||
" (17, \"Per Mertesacker\", \"Defender\", []),\n",
|
|
||||||
" (20, \"Jérôme Boateng\", \"Defender\", []),\n",
|
|
||||||
" (6, \"Sami Khedira\", \"Midfielder\", [29]),\n",
|
|
||||||
" (7, \"Bastian Schweinsteiger\", \"Midfielder\", []),\n",
|
|
||||||
" (8, \"Mesut Özil\", \"Midfielder\", []),\n",
|
|
||||||
" (13, \"Thomas Müller\", \"Midfielder\", [11]),\n",
|
|
||||||
" (14, \"Julian Draxler\", \"Midfielder\", []),\n",
|
|
||||||
" (18, \"Toni Kroos\", \"Midfielder\", [24, 26]),\n",
|
|
||||||
" (9, \"André Schürrle\", \"Striker\", [69, 79]),\n",
|
|
||||||
" (11, \"Miroslav Klose\", \"Striker\", [23]),\n",
|
|
||||||
" ],\n",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: Write a dictionary comprehension to derive a new `dict` object, called `brazilian_players`, that maps a Brazilian player's name to his position!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"brazilian_players = {...: ...}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"brazilian_players"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: Generalize the code fragment into a `get_players()` function: Passed a `team` name, it returns a `dict` object like `brazilian_players`. Verify that the function works for the German team as well!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def get_players(team):\n",
|
|
||||||
" \"\"\"Creates a dictionary mapping the players' names to their position.\"\"\"\n",
|
|
||||||
" return {...: ...}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"get_players(\"Germany\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Often, we are given a `dict` object like the one returned from `get_players()`: Its main characteristic is that it maps a large set of unique keys (i.e., the players' names) onto a smaller set of non-unique values (i.e., the positions).\n",
|
|
||||||
"\n",
|
|
||||||
"**Q3**: Create a generic `invert()` function that swaps the keys and values of a `mapping` argument passed to it and returns them in a *new* `dict` object! Ensure that *no* key gets lost! Verify your implementation with the `brazilian_players` dictionary!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Think of this as a grouping operation. The *new* values are `list` or `tuple` objects that hold the original keys. You may want to use either the [defaultdict <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.defaultdict) type from the [collections <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) or the [.setdefault() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html#dict.setdefault) method on the ordinary `dict` type."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def invert(mapping):\n",
|
|
||||||
" \"\"\"Invert the keys and values of a mapping argument.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"invert(brazilian_players)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: Write a `score_at_minute()` function: It takes two arguments, `team` and `minute`, and returns the number of goals the `team` has scored up until this time in the game.\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: The function may reference the global `players` for simplicity. Earn bonus points if you can write this in a one-line expression using some *reduction* function and a `generator` expression."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def score_at_minute(team, minute):\n",
|
|
||||||
" \"\"\"Determine the number of goals scored by a team until a given minute.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The score at half time was:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"score_at_minute(\"Brazil\", 45)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"score_at_minute(\"Germany\", 45)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The final score was:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"score_at_minute(\"Brazil\", 90)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"score_at_minute(\"Germany\", 90)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: Write a `goals_by_player()` function that takes an argument like the global `players`, and returns a `dict` object mapping the players to the number of goals they scored!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Do *not* \"hard code\" the names of the teams! Earn bonus points if you can solve it in a one-line `dict` comprehension."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def goals_by_player(players):\n",
|
|
||||||
" \"\"\"Create a dictionary mapping the players' names to the number of goals.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"goals_by_player(players)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q6**: Write a `dict` comprehension to filter out the players who did *not* score from the preceding result.\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Reference the `goals_by_player()` function from before."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"{...: ...}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q7**: Write a `all_goals()` function that takes one argument like the global `players` and returns a `list` object containing $2$-element `tuple` objects where the first element is the minute a player scored and the second his name! The list should be sorted by the time.\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: You may want to use either the built-in [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) function or the `list` type's [.sort() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html#list.sort) method. Earn bonus points if you can write a one-line expression with a `generator` expression."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def all_goals(players):\n",
|
|
||||||
" \"\"\"Create a time table of the individual goals.\"\"\"\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"all_goals(players)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q8**: Lastly, write a `summary()` function that takes one argument like the global `players` and prints out a concise report of the goals, the score at the half, and the final result.\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: Use the `all_goals()` and `score_at_minute()` functions from before.\n",
|
|
||||||
"\n",
|
|
||||||
"The output should look similar to this:\n",
|
|
||||||
"```\n",
|
|
||||||
"12' Gerd Müller scores\n",
|
|
||||||
"...\n",
|
|
||||||
"HALFTIME: TeamA 1 TeamB 2\n",
|
|
||||||
"77' Ronaldo scores\n",
|
|
||||||
"...\n",
|
|
||||||
"FINAL: TeamA 1 TeamB 3\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def summary(players):\n",
|
|
||||||
" \"\"\"Create a written summary of the game.\"\"\"\n",
|
|
||||||
" # Create two lists with the goals of either half.\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" # Print the goals of the first half.\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" # Print the half time score.\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" # Print the goals of the second half.\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
"\n",
|
|
||||||
" # Print the final score.\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ...\n",
|
|
||||||
" ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"summary(players)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,248 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/03_exercises.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 9: Mappings & Sets (Coding Exercises)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The exercises below assume that you have read the [second part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb) of Chapter 9.\n",
|
|
||||||
"\n",
|
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Memoization without Side Effects"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"It is considered *bad practice* to make a function and thereby its correctness dependent on a program's *global state*: For example, in the \"*Easy at second Glance: Fibonacci Numbers*\" section in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb#\"Easy-at-second-Glance\"-Example:-Fibonacci-Numbers--%28revisited%29), we use a global `memo` to store the Fibonacci numbers that have already been calculated.\n",
|
|
||||||
"\n",
|
|
||||||
"That `memo` dictionary could be \"manipulated.\" More often than not, such things happen by accident: Imagine we wrote two independent recursive functions that both rely on memoization to solve different problems, and, unintentionally, we made both work with the *same* global `memo`. As a result, we would observe \"random\" bugs depending on the order in which we executed these functions. Such bugs are hard to track down in practice.\n",
|
|
||||||
"\n",
|
|
||||||
"A common remedy is to avoid global state and pass intermediate results \"down\" the recursion tree in a \"hidden\" argument. By convention, we prefix parameter names with a single leading underscore `_`, such as with `_memo` below, to indicate that the caller of our `fibonacci()` function *must not* use it. Also, we make `_memo` a *keyword-only* argument to force ourselves to always explicitly name it in a function call. Because it is an **implementation detail**, the `_memo` parameter is *not* mentioned in the docstring.\n",
|
|
||||||
"\n",
|
|
||||||
"Your task is to complete this version of `fibonacci()` so that the function works *without* any **side effects** in the global scope."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### \"Easy at third Glance\" Example: [Fibonacci Numbers <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Fibonacci_number)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"code_folding": [],
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def fibonacci(i, *, debug=False, _memo=None):\n",
|
|
||||||
" \"\"\"Calculate the ith Fibonacci number.\n",
|
|
||||||
"\n",
|
|
||||||
" Args:\n",
|
|
||||||
" i (int): index of the Fibonacci number to calculate\n",
|
|
||||||
" debug (bool): show non-cached calls; defaults to False\n",
|
|
||||||
"\n",
|
|
||||||
" Returns:\n",
|
|
||||||
" ith_fibonacci (int)\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" # answer to Q1\n",
|
|
||||||
" if ...:\n",
|
|
||||||
" ... = {\n",
|
|
||||||
" 0: 0,\n",
|
|
||||||
" 1: 1,\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
" # answer to Q2\n",
|
|
||||||
" if ...:\n",
|
|
||||||
" return ...\n",
|
|
||||||
"\n",
|
|
||||||
" if debug: # added for didactical purposes\n",
|
|
||||||
" print(f\"fibonacci({i}) is calculated\")\n",
|
|
||||||
"\n",
|
|
||||||
" # answer to Q3\n",
|
|
||||||
" recurse = (\n",
|
|
||||||
" fibonacci(...)\n",
|
|
||||||
" + fibonacci(...)\n",
|
|
||||||
" )\n",
|
|
||||||
" # answer to Q4\n",
|
|
||||||
" ... = ...\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: When `fibonacci()` is initially called, `_memo` is set to `None`. So, there is *no* `dict` object yet. Implement the *two* base cases in the first `if` statement!\n",
|
|
||||||
"\n",
|
|
||||||
"Hints: All you need to do is create a *new* `dict` object with the results for `i=0` and `i=1`. This object is then passed on in the recursive function calls. Use the `is` operator in the `if` statement."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: When `fibonacci()` is called for non-base cases (i.e., `i > 1`), it first checks if the result is already in the `_memo`. Implement that step in the second `if` statement!\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: Use the early exit pattern."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3**: If `fibonacci()` is called for an `i` argument whose result is not yet in the `_memo`, it must calculate it with the usual recursive function calls. Fill in the arguments to the two recursive `fibonacci()` calls!\n",
|
|
||||||
"\n",
|
|
||||||
"Hint: You must pass on the hidden `_memo`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: Lastly, after the two recursive calls have returned, `fibonacci()` must store the `recurse` result for the given `i` in the `_memo` *before* returning it. Implement that logic!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: What happens to the hidden `_memo` after the initial call to `fibonacci()` returned? How many hidden `_memo` objects exist in memory during the entire computation?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Because `fibonacci()` is now independent of the *global state*, the same eleven recursive function calls are made each time! So, this `fibonacci()` is a **pure** function, meaning it has *no* side effects.\n",
|
|
||||||
"\n",
|
|
||||||
"**Q6**: Execute the following code cell a couple of times to observe that!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"fibonacci(12, debug=True) # = 13th Fibonacci number -> 11 recursive calls necessary"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The runtime of `fibonacci()` is now stable: There is no message that \"an intermediate result is being cached\" as in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb#\"Easy-at-second-Glance\"-Example:-Fibonacci-Numbers--%28revisited%29).\n",
|
|
||||||
"\n",
|
|
||||||
"**Q7**: Execute the following code cells a couple of times to observe that!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%timeit -n 1\n",
|
|
||||||
"fibonacci(99)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%timeit -n 1\n",
|
|
||||||
"fibonacci(999)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,970 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Clear All Outputs*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *before* reading this notebook to reset its output. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/05_appendix.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 9: Mappings & Sets (Appendix)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The [collections <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) provides specialized mapping types for common use cases."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## The `defaultdict` Type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The [defaultdict <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.defaultdict) type allows us to define a factory function that creates default values whenever we look up a key that does not yet exist. Ordinary `dict` objects would throw a `KeyError` exception in such situations.\n",
|
|
||||||
"\n",
|
|
||||||
"Let's say we have a `list` with *records* of goals scored during a soccer game. The records consist of the fields \"Country,\" \"Player,\" and the \"Time\" when a goal was scored. Our task is to group the goals by player and/or country."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"goals = [\n",
|
|
||||||
" (\"Germany\", \"Müller\", 11), (\"Germany\", \"Klose\", 23),\n",
|
|
||||||
" (\"Germany\", \"Kroos\", 24), (\"Germany\", \"Kroos\", 26),\n",
|
|
||||||
" (\"Germany\", \"Khedira\", 29), (\"Germany\", \"Schürrle\", 69),\n",
|
|
||||||
" (\"Germany\", \"Schürrle\", 79), (\"Brazil\", \"Oscar\", 90),\n",
|
|
||||||
"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Using a normal `dict` object, we have to tediously check if a player has already scored a goal before. If not, we must create a *new* `list` object with the first time the player scored. Otherwise, we append the goal to an already existing `list` object."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"{'Müller': [11],\n",
|
|
||||||
" 'Klose': [23],\n",
|
|
||||||
" 'Kroos': [24, 26],\n",
|
|
||||||
" 'Khedira': [29],\n",
|
|
||||||
" 'Schürrle': [69, 79],\n",
|
|
||||||
" 'Oscar': [90]}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"goals_by_player = {}\n",
|
|
||||||
"\n",
|
|
||||||
"for _, player, minute in goals:\n",
|
|
||||||
" if player not in goals_by_player:\n",
|
|
||||||
" goals_by_player[player] = [minute]\n",
|
|
||||||
" else:\n",
|
|
||||||
" goals_by_player[player].append(minute)\n",
|
|
||||||
"\n",
|
|
||||||
"goals_by_player"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Instead, with a `defaultdict` object, we can portray the code fragment's intent in a concise form. We pass a reference to the [list() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-list) built-in to `defaultdict`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from collections import defaultdict"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"defaultdict(list,\n",
|
|
||||||
" {'Müller': [11],\n",
|
|
||||||
" 'Klose': [23],\n",
|
|
||||||
" 'Kroos': [24, 26],\n",
|
|
||||||
" 'Khedira': [29],\n",
|
|
||||||
" 'Schürrle': [69, 79],\n",
|
|
||||||
" 'Oscar': [90]})"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"goals_by_player = defaultdict(list)\n",
|
|
||||||
"\n",
|
|
||||||
"for _, player, minute in goals:\n",
|
|
||||||
" goals_by_player[player].append(minute)\n",
|
|
||||||
"\n",
|
|
||||||
"goals_by_player"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"collections.defaultdict"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"type(goals_by_player)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A reference to the factory function is stored in the `default_factory` attribute."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"list"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"goals_by_player.default_factory"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"If we want this code to produce a normal `dict` object, we pass `goals_by_player` to the [dict() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-dict) constructor."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 7,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"{'Müller': [11],\n",
|
|
||||||
" 'Klose': [23],\n",
|
|
||||||
" 'Kroos': [24, 26],\n",
|
|
||||||
" 'Khedira': [29],\n",
|
|
||||||
" 'Schürrle': [69, 79],\n",
|
|
||||||
" 'Oscar': [90]}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 7,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"dict(goals_by_player)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Being creative, we use a factory function, created with a `lambda` expression, that returns another [defaultdict <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.defaultdict) with [list() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#func-list) as its factory to group on the country and the player level simultaneously."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"defaultdict(<function __main__.<lambda>()>,\n",
|
|
||||||
" {'Germany': defaultdict(list,\n",
|
|
||||||
" {'Müller': [11],\n",
|
|
||||||
" 'Klose': [23],\n",
|
|
||||||
" 'Kroos': [24, 26],\n",
|
|
||||||
" 'Khedira': [29],\n",
|
|
||||||
" 'Schürrle': [69, 79]}),\n",
|
|
||||||
" 'Brazil': defaultdict(list, {'Oscar': [90]})})"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 8,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"goals_by_country_and_player = defaultdict(lambda: defaultdict(list))\n",
|
|
||||||
"\n",
|
|
||||||
"for country, player, minute in goals:\n",
|
|
||||||
" goals_by_country_and_player[country][player].append(minute)\n",
|
|
||||||
"\n",
|
|
||||||
"goals_by_country_and_player"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Conversion into a normal and nested `dict` object is now a bit tricky but can be achieved in one line with a comprehension."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"{'Germany': {'Müller': [11],\n",
|
|
||||||
" 'Klose': [23],\n",
|
|
||||||
" 'Kroos': [24, 26],\n",
|
|
||||||
" 'Khedira': [29],\n",
|
|
||||||
" 'Schürrle': [69, 79]},\n",
|
|
||||||
" 'Brazil': {'Oscar': [90]}}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 9,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"{country: dict(by_player) for country, by_player in goals_by_country_and_player.items()}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## The `Counter` Type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"A common task is to count the number of occurrences of elements in an iterable.\n",
|
|
||||||
"\n",
|
|
||||||
"The [Counter <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.Counter) type provides an easy-to-use interface that can be called with any iterable and returns a `dict`-like object of type `Counter` that maps each unique elements to the number of times it occurs.\n",
|
|
||||||
"\n",
|
|
||||||
"To continue the previous example, let's create an overview that shows how many goals a player scorred. We use a generator expression as the argument to `Counter`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"[('Germany', 'Müller', 11),\n",
|
|
||||||
" ('Germany', 'Klose', 23),\n",
|
|
||||||
" ('Germany', 'Kroos', 24),\n",
|
|
||||||
" ('Germany', 'Kroos', 26),\n",
|
|
||||||
" ('Germany', 'Khedira', 29),\n",
|
|
||||||
" ('Germany', 'Schürrle', 69),\n",
|
|
||||||
" ('Germany', 'Schürrle', 79),\n",
|
|
||||||
" ('Brazil', 'Oscar', 90)]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"goals"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 11,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from collections import Counter"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"scorers = Counter(x[1] for x in goals)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"Counter({'Kroos': 2,\n",
|
|
||||||
" 'Schürrle': 2,\n",
|
|
||||||
" 'Müller': 1,\n",
|
|
||||||
" 'Klose': 1,\n",
|
|
||||||
" 'Khedira': 1,\n",
|
|
||||||
" 'Oscar': 1})"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 13,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"collections.Counter"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 14,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"type(scorers)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Now we can look up individual players. `scores` behaves like a normal dictionary with regard to key look-ups."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"1"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers[\"Müller\"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"By default, it returns `0` if a key is not found. So, we do not have to handle a `KeyError`."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"0"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 16,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers[\"Lahm\"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"`Counter` objects have a [.most_common() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.Counter.most_common) method that returns a `list` object containing $2$-element `tuple` objects, where the first element is the element from the original iterable and the second the number of occurrences. The `list` object is sorted in descending order of occurrences."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"[('Kroos', 2), ('Schürrle', 2)]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 17,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers.most_common(2)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We can increase the count of individual entries with the [.update() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.Counter.update) method: That takes an *iterable* of the elements we want to count.\n",
|
|
||||||
"\n",
|
|
||||||
"Imagine if [Philipp Lahm <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Philipp_Lahm) had also scored against Brazil."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 18,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"scorers.update([\"Lahm\"])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 19,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"Counter({'Kroos': 2,\n",
|
|
||||||
" 'Schürrle': 2,\n",
|
|
||||||
" 'Müller': 1,\n",
|
|
||||||
" 'Klose': 1,\n",
|
|
||||||
" 'Khedira': 1,\n",
|
|
||||||
" 'Oscar': 1,\n",
|
|
||||||
" 'Lahm': 1})"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 19,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"If we use a `str` object as the argument instead, each individual character is treated as an element to be updated. That is most likely not what we want."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 20,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"scorers.update(\"Lahm\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 21,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"Counter({'Kroos': 2,\n",
|
|
||||||
" 'Schürrle': 2,\n",
|
|
||||||
" 'Müller': 1,\n",
|
|
||||||
" 'Klose': 1,\n",
|
|
||||||
" 'Khedira': 1,\n",
|
|
||||||
" 'Oscar': 1,\n",
|
|
||||||
" 'Lahm': 1,\n",
|
|
||||||
" 'L': 1,\n",
|
|
||||||
" 'a': 1,\n",
|
|
||||||
" 'h': 1,\n",
|
|
||||||
" 'm': 1})"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 21,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"scorers"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"## The `ChainMap` Type"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Consider `to_words`, `more_words`, and `even_more_words` below. Instead of merging the items of the three `dict` objects together into a *new* one, we want to create an object that behaves as if it contained all the unified items in it without materializing them in memory a second time."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 22,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"to_words = {\n",
|
|
||||||
" 0: \"zero\",\n",
|
|
||||||
" 1: \"one\",\n",
|
|
||||||
" 2: \"two\",\n",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 23,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"more_words = {\n",
|
|
||||||
" 2: \"TWO\", # to illustrate a point\n",
|
|
||||||
" 3: \"three\",\n",
|
|
||||||
" 4: \"four\",\n",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 24,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"even_more_words = {\n",
|
|
||||||
" 4: \"FOUR\", # to illustrate a point\n",
|
|
||||||
" 5: \"five\",\n",
|
|
||||||
" 6: \"six\",\n",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"The [ChainMap <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/collections.html#collections.ChainMap) type allows us to do precisely that."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 25,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from collections import ChainMap"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"We simply pass all mappings as positional arguments to `ChainMap` and obtain a **proxy** object that occupies almost no memory but gives us access to the union of all the items."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 26,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"chain = ChainMap(to_words, more_words, even_more_words)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"Let's loop over the items in `chain` and see what is \"in\" it. The order is obviously *unpredictable* but all seven items we expected are there. Keys of later mappings do *not* overwrite earlier keys."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 27,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"4 four\n",
|
|
||||||
"5 five\n",
|
|
||||||
"6 six\n",
|
|
||||||
"2 two\n",
|
|
||||||
"3 three\n",
|
|
||||||
"0 zero\n",
|
|
||||||
"1 one\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"for number, word in chain.items():\n",
|
|
||||||
" print(number, word)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"When looking up a non-existent key, `ChainMap` objects raise a `KeyError` just like normal `dict` objects would."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 28,
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "KeyError",
|
|
||||||
"evalue": "10",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
|
||||||
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
|
|
||||||
"Cell \u001b[0;32mIn[28], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mchain\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m]\u001b[49m\n",
|
|
||||||
"File \u001b[0;32m/usr/lib64/python3.12/collections/__init__.py:1014\u001b[0m, in \u001b[0;36mChainMap.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 1012\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[1;32m 1013\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[0;32m-> 1014\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__missing__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n",
|
|
||||||
"File \u001b[0;32m/usr/lib64/python3.12/collections/__init__.py:1006\u001b[0m, in \u001b[0;36mChainMap.__missing__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 1005\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__missing__\u001b[39m(\u001b[38;5;28mself\u001b[39m, key):\n\u001b[0;32m-> 1006\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key)\n",
|
|
||||||
"\u001b[0;31mKeyError\u001b[0m: 10"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"chain[10]"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 9: Mappings & Sets (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"`dict` objects are **mutable** one-to-one **mappings** from a set of **key** objects to a set of **value** objects. The association between a key-value pair is also called **item**.\n",
|
|
||||||
"\n",
|
|
||||||
"The items contained in a `dict` object have **no order** that is *predictable*.\n",
|
|
||||||
"\n",
|
|
||||||
"The underlying **data structure** of the `dict` type are **hash tables**. They make key look-ups *extremely* fast by converting the items' keys into *deterministic* hash values specifiying *precisely* one of a fixed number of equally \"wide\" buckets in which an item's references are stored. A limitation is that objects used as keys must be *immutable* (for technical reasons) and *unique* (for practical reasons).\n",
|
|
||||||
"\n",
|
|
||||||
"A `set` object is a **mutable** and **unordered collection** of **immutable** objects. The `set` type mimics sets we know from math."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
7415
09_mappings_00_content.ipynb
Normal file
7415
09_mappings_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,14 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 9: Mappings & Sets (Review Questions)"
|
"# Chapter 9: Mappings & Sets"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb), and [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/04_content.ipynb) part of Chapter 9.\n",
|
"## Content Review"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The questions below assume that you have read [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
||||||
]
|
]
|
||||||
|
|
@ -20,7 +27,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## Essay Questions "
|
"### Essay Questions "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -69,7 +76,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q4**: Whereas *key* **look-ups** in a `dict` object run in so-called **[constant time <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Time_complexity#Constant_time)** (i.e., *extremely* fast), that does not hold for *reverse* look-ups. Why is that?"
|
"**Q4**: Whereas *key* **look-ups** in a `dict` object run in so-called **[constant time <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Time_complexity#Constant_time)** (i.e., *extremely* fast), that does not hold for *reverse* look-ups. Why is that?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -99,9 +106,10 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q6**: **Memoization** is an essential concept to know to solve problems in the real world. Together with the idea of **recursion**, it enables us to solve problems in a \"backwards\" fashion *effectively*.\n",
|
"**Q6**: **Memoization** is an essential concept to know to solve problems in the real world. Together with the idea of **recursion**, it enables us to solve problems in a \"backwards\" fashion *effectively*.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Compare the **recursive** formulation of `fibonacci()` in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb#\"Easy-at-second-Glance\"-Example:-Fibonacci-Numbers--(revisited)), the \"*Easy at second Glance*\" example, with the **iterative** version in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Hard at first Glance*\" example!\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"How are they similar and how do they differ? Also consider how the flow of execution behaves when the functions are being executed."
|
"Compare the **recursive** formulation of `fibonacci()` in [Chapter 8 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb#\"Easy-at-third-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Easy at second Glance*\" example, with the **iterative** version in [Chapter 4 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Hard at first Glance*\" example!\n",
|
||||||
|
"\n",
|
||||||
|
"How are they similar and how do they differ?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -115,7 +123,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7**: How are the `set` and the `dict` types related? How could we use the latter to mimic the former?"
|
"**Q7**: How are the `set` and the `dict` type related? How could we use the latter to mimic the former?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -129,7 +137,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## True / False Questions"
|
"### True / False Questions"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -185,7 +193,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q11**: A `dict` object's [.update() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/stdtypes.html#dict.update) method only inserts key-value pairs whose key is *not* yet in the `dict` object. So, it does *not* overwrite anything."
|
"**Q11**: A `dict` object's [update() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/stdtypes.html#dict.update) method only inserts key-value pairs whose key is *not* yet in the `dict` object. So, it does *not* overwrite anything."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -226,7 +234,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
631
09_mappings_02_exercises.ipynb
Normal file
631
09_mappings_02_exercises.ipynb
Normal file
|
|
@ -0,0 +1,631 @@
|
||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/09_mappings_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# Chapter 9: Mappings & Sets"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Coding Exercises"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The exercises below assume that you have read [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb) in the book.\n",
|
||||||
|
"\n",
|
||||||
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Working with Nested Data"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Let's write some code to analyze the historic soccer game [Brazil vs. Germany <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Brazil_v_Germany_%282014_FIFA_World_Cup%29) during the 2014 World Cup.\n",
|
||||||
|
"\n",
|
||||||
|
"Below, `players` consists of two nested `dict` objects, one for each team, that hold `tuple` objects (i.e., records) with information on the players. Besides the jersey number, name, and position, each `tuple` objects contains a `list` object with the times when the player scored."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"players = {\n",
|
||||||
|
" \"Brazil\": [\n",
|
||||||
|
" (12, \"Júlio César\", \"Goalkeeper\", []),\n",
|
||||||
|
" (4, \"David Luiz\", \"Defender\", []),\n",
|
||||||
|
" (6, \"Marcelo\", \"Defender\", []),\n",
|
||||||
|
" (13, \"Dante\", \"Defender\", []),\n",
|
||||||
|
" (23, \"Maicon\", \"Defender\", []),\n",
|
||||||
|
" (5, \"Fernandinho\", \"Midfielder\", []),\n",
|
||||||
|
" (7, \"Hulk\", \"Midfielder\", []),\n",
|
||||||
|
" (8, \"Paulinho\", \"Midfielder\", []),\n",
|
||||||
|
" (11, \"Oscar\", \"Midfielder\", [90]),\n",
|
||||||
|
" (16, \"Ramires\", \"Midfielder\", []),\n",
|
||||||
|
" (17, \"Luiz Gustavo\", \"Midfielder\", []),\n",
|
||||||
|
" (19, \"Willian\", \"Midfielder\", []),\n",
|
||||||
|
" (9, \"Fred\", \"Striker\", []),\n",
|
||||||
|
" ],\n",
|
||||||
|
" \"Germany\": [\n",
|
||||||
|
" (1, \"Manuel Neuer\", \"Goalkeeper\", []),\n",
|
||||||
|
" (4, \"Benedikt Höwedes\", \"Defender\", []),\n",
|
||||||
|
" (5, \"Mats Hummels\", \"Defender\", []),\n",
|
||||||
|
" (16, \"Philipp Lahm\", \"Defender\", []),\n",
|
||||||
|
" (17, \"Per Mertesacker\", \"Defender\", []),\n",
|
||||||
|
" (20, \"Jérôme Boateng\", \"Defender\", []),\n",
|
||||||
|
" (6, \"Sami Khedira\", \"Midfielder\", [29]),\n",
|
||||||
|
" (7, \"Bastian Schweinsteiger\", \"Midfielder\", []),\n",
|
||||||
|
" (8, \"Mesut Özil\", \"Midfielder\", []),\n",
|
||||||
|
" (13, \"Thomas Müller\", \"Midfielder\", [11]),\n",
|
||||||
|
" (14, \"Julian Draxler\", \"Midfielder\", []),\n",
|
||||||
|
" (18, \"Toni Kroos\", \"Midfielder\", [24, 26]),\n",
|
||||||
|
" (9, \"André Schürrle\", \"Striker\", [69, 79]),\n",
|
||||||
|
" (11, \"Miroslav Klose\", \"Striker\", [23]),\n",
|
||||||
|
" ],\n",
|
||||||
|
"}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.1**: Write a dictionary comprehension to derive a new `dict` object, called `brazilian_players`, that maps a Brazilian player's name to his position!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"brazilian_players = {...: ...}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"brazilian_players"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.2**: Generalize the code fragment into a `get_players()` function: Passed a `team` name, it returns a `dict` object like `brazilian_players`. Verify that the function works for the German team as well!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def get_players(team):\n",
|
||||||
|
" \"\"\"Creates a dictionary mapping the players' names to their position.\"\"\"\n",
|
||||||
|
" return {...: ...}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"get_players(\"Germany\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Often, we are given a `dict` object like the one returned from `get_players()`: Its main characteristic is that it maps a large set of unique keys (i.e., the players' names) onto a smaller set of non-unique values (i.e., the positions).\n",
|
||||||
|
"\n",
|
||||||
|
"**Q1.3**: Create a generic `invert()` function that swaps the keys and values of a `mapping` argument passed to it and returns them in a *new* `dict` object! Ensure that *no* key gets lost! Verify your implementation with the `brazilian_players` dictionary!\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: Think of this as a grouping operation. The *new* values are `list` or `tuple` objects that hold the original keys. You may want to use either the [defaultdict <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/collections.html#collections.defaultdict) type from the [collections <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/collections.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) or the [setdefault() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/stdtypes.html#dict.setdefault) method on the ordinary `dict` type."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def invert(mapping):\n",
|
||||||
|
" \"\"\"Invert the keys and values of a mapping argument.\"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"invert(brazilian_players)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.4**: Write a `score_at_minute()` function: It takes two arguments, `team` and `minute`, and returns the number of goals the `team` has scored up until this time in the game.\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: The function may reference the global `players` for simplicity. Earn bonus points if you can write this in a one-line expression using some *reduction* function and a *generator expression*."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def score_at_minute(team, minute):\n",
|
||||||
|
" \"\"\"Determine the number of goals scored by a team until a given minute.\"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The score at half time was:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"score_at_minute(\"Brazil\", 45)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"score_at_minute(\"Germany\", 45)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The final score was:"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"score_at_minute(\"Brazil\", 90)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"score_at_minute(\"Germany\", 90)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.5**: Write a `goals_by_player()` function that takes an argument like the global `players`, and returns a `dict` object mapping the players to the number of goals they scored!\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: Do *not* \"hard code\" the names of the teams! Earn bonus points if you can solve it in a one-line dictionary comprehension."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def goals_by_player(players):\n",
|
||||||
|
" \"\"\"Create a dictionary mapping the players' names to the number of goals.\"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"goals_by_player(players)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.6**: Write a *dictionary comprehension* to filter out the players who did *not* score from the preceding result. Then, write a *set comprehension* that does the same but discards the number of goals scored.\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: Reference the `goals_by_player()` function from before."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"{...: ...}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"{...}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.7**: Write a `all_goals()` function that takes one argument like the global `players` and returns a `list` object containing $2$-element `tuple` objects where the first element is the minute a player scored and the second his name! The list should be sorted by the time.\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: You may want to use either the built-in [sorted() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/functions.html#sorted) function or the `list` type's [sort() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/stdtypes.html#list.sort) method. Earn bonus points if you can write a one-line expression with a *generator expression*."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def all_goals(players):\n",
|
||||||
|
" \"\"\"Create a time table of the individual goals.\"\"\"\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"all_goals(players)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q1.8**: Lastly, write a `summary()` function that takes one argument like the global `players` and prints out a concise report of the goals, the score at the half, and the final result.\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: Use the `all_goals()` and `score_at_minute()` functions from before.\n",
|
||||||
|
"\n",
|
||||||
|
"The output should look similar to this:\n",
|
||||||
|
"```\n",
|
||||||
|
"12' Gerd Müller scores\n",
|
||||||
|
"...\n",
|
||||||
|
"HALFTIME: TeamA 1 TeamB 2\n",
|
||||||
|
"77' Ronaldo scores\n",
|
||||||
|
"...\n",
|
||||||
|
"FINAL: TeamA 1 TeamB 3\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def summary(players):\n",
|
||||||
|
" \"\"\"Create a written summary of the game.\"\"\"\n",
|
||||||
|
" # Create two lists with the goals of either half.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Print the goals of the first half.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Print the half time score.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Print the goals of the second half.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
"\n",
|
||||||
|
" # Print the final score.\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ...\n",
|
||||||
|
" ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"summary(players)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Memoization without Side Effects"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"It is considered *bad practice* to make a function and thereby its correctness dependent on a program's *global state*: For example, in the \"*Easy at second Glance: Fibonacci Numbers*\" section in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb#\"Easy-at-second-Glance\"-Example:-Fibonacci-Numbers--%28revisited%29), we use a global `memo` to store the Fibonacci numbers that have already been calculated.\n",
|
||||||
|
"\n",
|
||||||
|
"That `memo` dictionary could be \"manipulated.\" More often than not, such things happen by accident: Imagine we wrote two independent recursive functions that both rely on memoization to solve different problems, and, unintentionally, we made both work with the *same* global `memo`. As a result, we would observe \"random\" bugs depending on the order in which we executed these functions. Such bugs are hard to track down in practice.\n",
|
||||||
|
"\n",
|
||||||
|
"A common remedy is to avoid global state and pass intermediate results \"down\" the recursion tree in a \"hidden\" argument. By convention, we prefix parameter names with a single leading underscore `_`, such as with `_memo` below, to indicate that the caller of our `fibonacci()` function *must not* use it. Also, we make `_memo` a *keyword-only* argument to force ourselves to always explicitly name it in a function call. Because it is an **implementation detail**, the `_memo` parameter is *not* mentioned in the docstring.\n",
|
||||||
|
"\n",
|
||||||
|
"Your task is to complete this version of `fibonacci()` so that the function works *without* any **side effects** in the global scope."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"#### \"Easy at third Glance\" Example: [Fibonacci Numbers <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Fibonacci_number)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {
|
||||||
|
"code_folding": [],
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def fibonacci(i, *, debug=False, _memo=None):\n",
|
||||||
|
" \"\"\"Calculate the ith Fibonacci number.\n",
|
||||||
|
"\n",
|
||||||
|
" Args:\n",
|
||||||
|
" i (int): index of the Fibonacci number to calculate\n",
|
||||||
|
" debug (bool): show non-cached calls; defaults to False\n",
|
||||||
|
"\n",
|
||||||
|
" Returns:\n",
|
||||||
|
" ith_fibonacci (int)\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # answer to Q2.1\n",
|
||||||
|
" if ...:\n",
|
||||||
|
" ... = {\n",
|
||||||
|
" 0: 0,\n",
|
||||||
|
" 1: 1,\n",
|
||||||
|
" }\n",
|
||||||
|
"\n",
|
||||||
|
" # answer to Q2.2\n",
|
||||||
|
" if ...:\n",
|
||||||
|
" return ...\n",
|
||||||
|
"\n",
|
||||||
|
" if debug: # added for didactical purposes\n",
|
||||||
|
" print(f\"fibonacci({i}) is calculated\")\n",
|
||||||
|
"\n",
|
||||||
|
" # answer to Q2.3\n",
|
||||||
|
" recurse = (\n",
|
||||||
|
" fibonacci(...)\n",
|
||||||
|
" + fibonacci(...)\n",
|
||||||
|
" )\n",
|
||||||
|
" # answer to Q2.4\n",
|
||||||
|
" ... = ...\n",
|
||||||
|
" return ..."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"**Q2.1**: When `fibonacci()` is initially called, `_memo` is set to `None`. So, there is *no* `dict` object yet. Implement the *two* base cases in the first `if` statement!\n",
|
||||||
|
"\n",
|
||||||
|
"Hints: All you need to do is create a *new* `dict` object with the results for `i=0` and `i=1`. This object is then passed on in the recursive function calls. Use the `is` operator in the `if` statement."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.2**: When `fibonacci()` is called for non-base cases (i.e., `i > 1`), it first checks if the result is already in the `_memo`. Implement that step in the second `if` statement!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: Use the early exit pattern."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.3**: If `fibonacci()` is called for an `i` argument whose result is not yet in the `_memo`, it must calculate it with the usual recursive function calls. Fill in the arguments to the two recursive `fibonacci()` calls!\n",
|
||||||
|
"\n",
|
||||||
|
"Hint: You must pass on the hidden `_memo`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.4**: Lastly, after the two recursive calls have returned, `fibonacci()` must store the `recurse` result for the given `i` in the `_memo` *before* returning it. Implement that logic!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Q2.5**: What happens to the hidden `_memo` after the initial call to `fibonacci()` returned? How many hidden `_memo` objects exist in memory during the entire computation?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
" < your answer >"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Because `fibonacci()` is now independent of the *global state*, the same eleven recursive function calls are made each time! So, this `fibonacci()` is a **pure** function, meaning it has *no* side effects.\n",
|
||||||
|
"\n",
|
||||||
|
"**Q2.6**: Execute the following code cell a couple of times to observe that!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": "skip"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"fibonacci(12, debug=True) # = 13th Fibonacci number -> 11 recursive calls necessary"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"The runtime of `fibonacci()` is now stable: Ther is no message that \"an intermediate result is being cached\" as in [Chapter 9 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb#\"Easy-at-second-Glance\"-Example:-Fibonacci-Numbers--%28revisited%29).\n",
|
||||||
|
"\n",
|
||||||
|
"**Q2.7**: Execute the following code cells a couple of times to observe that!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"%%timeit -n 1\n",
|
||||||
|
"fibonacci(99)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"%%timeit -n 1\n",
|
||||||
|
"fibonacci(999)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.7.4"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"base_numbering": 1,
|
||||||
|
"nav_menu": {},
|
||||||
|
"number_sections": false,
|
||||||
|
"sideBar": true,
|
||||||
|
"skip_h1_title": true,
|
||||||
|
"title_cell": "Table of Contents",
|
||||||
|
"title_sidebar": "Contents",
|
||||||
|
"toc_cell": false,
|
||||||
|
"toc_position": {},
|
||||||
|
"toc_section_display": false,
|
||||||
|
"toc_window_display": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 4
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Here, a new section on `numpy` Arrays and, maybe, `pandas` DataFrames will be added.
|
|
||||||
7688
10_classes_00_content.ipynb
Normal file
7688
10_classes_00_content.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -4,21 +4,21 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) *after* finishing the exercises to ensure that your solution runs top to bottom *without* any errors. If you cannot run this file on your machine, you may want to open it [in the cloud <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/01_exercises.ipynb)."
|
"**Important**: Click on \"*Kernel*\" > \"*Restart Kernel and Run All*\" *after* finishing the exercises in [JupyterLab <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_jp.png\">](https://jupyterlab.readthedocs.io/en/stable/) (e.g., in the cloud on [MyBinder <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_mb.png\">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/10_classes_02_exercises.ipynb)) to ensure that your solution runs top to bottom *without* any errors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Chapter 11: Classes & Instances (Coding Exercises)"
|
"# Chapter 10: Classes & Instances"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The exercises below assume that you have read the [first part <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb) of Chapter 11.\n",
|
"The exercises below assume that you have read [Chapter 10 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_00_content.ipynb) in the book.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
"The `...`'s in the code cells indicate where you need to fill in code snippets. The number of `...`'s within a code cell give you a rough idea of how many lines of code are needed to solve the task. You should not need to create any additional code cells for your final solution. However, you may want to use temporary code cells to try out some ideas."
|
||||||
]
|
]
|
||||||
|
|
@ -34,9 +34,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"This notebook is a hands-on and tutorial-like application to show how to load data from web services like [Google Maps](https://developers.google.com/maps) and use them to solve a logistics problem, namely a **[Traveling Salesman Problem <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Traveling_salesman_problem)**.\n",
|
"This notebook is a hands-on and tutorial-like application to show how to load data from web services like [Google Maps](https://developers.google.com/maps) and use them to solve a logistics problem, namely a **[Traveling Salesman Problem <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Traveling_salesman_problem)**.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Imagine that a tourist lands at Berlin's [Tegel Airport <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Berlin_Tegel_Airport) in the morning and has his \"connecting\" flight from [Schönefeld Airport <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Berlin_Sch%C3%B6nefeld_Airport) in the evening. By the time, the flights were scheduled, the airline thought that there would be only one airport in Berlin.\n",
|
"Imagine that a tourist lands at Berlin's [Tegel Airport <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Berlin_Tegel_Airport) in the morning and has his \"connecting\" flight from [Schönefeld Airport <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Berlin_Sch%C3%B6nefeld_Airport) in the evening. By the time, the flights were scheduled, the airline thought that there would be only one airport in Berlin.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Having never been in Berlin before, the tourist wants to come up with a plan of sights that he can visit with a rental car on his way from Tegel to Schönefeld.\n",
|
"Having never been in Berlin before, the tourist wants to come up with a plan of sights that he can visit with a rental car on his way from Tegel to Schönefeld.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -70,9 +70,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"With just the street addresses, however, he cannot calculate a route. He needs `latitude`-`longitude` coordinates instead. While he could just open a site like [Google Maps](https://www.google.com/maps) in a web browser, he wonders if he can download the data with a bit of Python code using a [web API <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Web_API) offered by [Google](https://www.google.com).\n",
|
"With just the street addresses, however, he cannot calculate a route. He needs `latitude`-`longitude` coordinates instead. While he could just open a site like [Google Maps](https://www.google.com/maps) in a web browser, he wonders if he can download the data with a bit of Python code using a [web API <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Web_API) offered by [Google](https://www.google.com).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"So, in this notebook, we solve the entire problem with code."
|
"So, in this notebook, we solve the entire problem with code. To keep everything clean and maintainable, we use Python's object-oriented features (cf., [Chapter 10 <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_00_content.ipynb) to implement the solution."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -110,9 +110,9 @@
|
||||||
"source": [
|
"source": [
|
||||||
"To use external web services, our application needs to make HTTP requests just like web browsers do when surfing the web.\n",
|
"To use external web services, our application needs to make HTTP requests just like web browsers do when surfing the web.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"We do not have to implement this on our own. Instead, we use the official Python Client for the Google Maps Services provided by Google in one of its corporate [GitHub repositories <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/googlemaps).\n",
|
"We do not have to implement this on our own. Instead, we use the official Python Client for the Google Maps Services provided by Google in one of its corporate [GitHub repositories <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/googlemaps).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q3**: Familiarize yourself with the [googlemaps <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/googlemaps/google-maps-services-python) package! Then, install it with the `pip` command line tool!"
|
"**Q3**: Familiarize yourself with the [googlemaps <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/googlemaps/google-maps-services-python) package! Then, install it with the `pip` command line tool!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -211,7 +211,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q7**: Capture the first and only search result in the `brandenburg_gate` variable and \"pretty print\" it with the help of the [pprint() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/pprint.html#pprint.pprint) function in the [pprint <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/pprint.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html)!"
|
"**Q7**: Capture the first and only search result in the `brandenburg_gate` variable and \"pretty print\" it with the help of the [pprint() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/pprint.html#pprint.pprint) function in the [pprint <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/pprint.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html)!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -270,15 +270,15 @@
|
||||||
"source": [
|
"source": [
|
||||||
"To keep our code readable and maintainable, we create a `Place` class to manage the API results in a clean way.\n",
|
"To keep our code readable and maintainable, we create a `Place` class to manage the API results in a clean way.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `.__init__()` method takes a `street_address` (e.g., an element of `sights`) and a `client` argument (e.g., an object like `api`) and stores them on `self`. The place's `.name` is parsed out of the `street_address` as well: It is the part before the first comma. Also, the instance attributes `.latitude`, `.longitude`, and `.place_id` are initialized to `None`.\n",
|
"The `__init__()` method takes a `street_address` (e.g., an element of `sights`) and a `client` argument (e.g., an object like `api`) and stores them on `self`. The place's `name` is parsed out of the `street_address` as well: It is the part before the first comma. Also, the instance attributes `latitude`, `longitude`, and `place_id` are initialized to `None`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q8**: Finish the `.__init__()` method according to the description!\n",
|
"**Q8**: Finish the `__init__()` method according to the description!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `.sync_from_google()` method uses the internally kept `client` and synchronizes the place's state with the [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start). In particular, it updates the `.address` with the `formatted_address` and stores the values for `.latitude`, `.longitude`, and `.place_id`. It enables method chaining.\n",
|
"The `sync_from_google()` method uses the internally kept `client` and synchronizes the place's state with the [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start). In particular, it updates the `address` with the `formatted_address` and stores the values for `latitude`, `longitude`, and `place_id`. It enables method chaining.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q9**: Implement the `.sync_from_google()` method according to the description!\n",
|
"**Q9**: Implement the `sync_from_google()` method according to the description!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q10**: Add a read-only `.location` property on the `Place` class that returns the `.latitude` and `.longitude` as a `tuple`!"
|
"**Q10**: Add a read-only `location` property on the `Place` class that returns the `latitude` and `longitude` as a `tuple`!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -370,9 +370,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Now, we can obtain the geo-data from the [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start) in a clean way. As we enabled method chaining for `.sync_from_google()`, we get back the instance after calling the method.\n",
|
"Now, we can obtain the geo-data from the [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start) in a clean way. As we enabled method chaining for `sync_from_google()`, we get back the instance after calling the method.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q13**: Verify that the `.sync_from_google()` method works!"
|
"**Q13**: Verify that the `sync_from_google()` method works!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -422,7 +422,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q14**: Add an alternative constructor method named `.from_addresses()` that takes an `addresses`, a `client`, and a `sync` argument! `addresses` is a finite iterable of `str` objects (e.g., like `sights`). The method returns a `list` of `Place`s, one for each `str` in `addresses`. All `Place`s are initialized with the same `client`. `sync` is a flag and defaults to `False`. If it is set to `True`, the alternative constructor invokes the `.sync_from_google()` method on the `Place`s before returning them."
|
"**Q14**: Add an alternative constructor method named `from_addresses()` that takes an `addresses`, a `client`, and a `sync` argument! `addresses` is a finite iterable of `str` objects (e.g., like `sights`). The method returns a `list` of `Place`s, one for each `str` in `addresses`. All `Place`s are initialized with the same `client`. `sync` is a flag and defaults to `False`. If it is set to `True`, the alternative constructor invokes the `sync_from_google()` method on the `Place`s before returning them."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -494,9 +494,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"For geo-data it always makes sense to plot them on a map. We use the third-party library [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium) to achieve that.\n",
|
"For geo-data it always makes sense to plot them on a map. We use the third-party library [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium) to achieve that.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q16**: Familiarize yourself with [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium) and install it with the `pip` command line tool!"
|
"**Q16**: Familiarize yourself with [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium) and install it with the `pip` command line tool!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -562,7 +562,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In order to put something on the map, [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium) works with so-called `Marker` objects.\n",
|
"In order to put something on the map, [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium) works with so-called `Marker` objects.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q18**: Review its docstring and then create a marker `m` with the location data of Brandenburg Gate! Use the `brandenburg_gate` object from above!\n",
|
"**Q18**: Review its docstring and then create a marker `m` with the location data of Brandenburg Gate! Use the `brandenburg_gate` object from above!\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -636,7 +636,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q20**: Finish the `.as_marker()` method that returns a `Marker` instance when invoked on a `Place` instance! The method takes an optional `color` argument that uses [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium)'s `Icon` type to control the color of the marker."
|
"**Q20**: Finish the `as_marker()` method that returns a `Marker` instance when invoked on a `Place` instance! The method takes an optional `color` argument that uses [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium)'s `Icon` type to control the color of the marker."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -680,7 +680,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"**Q21**: Execute the next code cells that create a new `Place` and obtain a `Marker` for it!\n",
|
"**Q21**: Execute the next code cells that create a new `Place` and obtain a `Marker` for it!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Notes: Without synchronization, we get a `RuntimeError`. `.as_marker()` can be chained right after `.sync_from_google()`"
|
"Notes: Without synchronization, we get a `RuntimeError`. `as_marker()` can be chained right after `sync_from_google()`"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -714,7 +714,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Q22**: Use the alternative `.from_addresses()` constructor to create a `list` named `places` with already synced `Place`s!"
|
"**Q22**: Use the alternative `from_addresses()` constructor to create a `list` named `places` with already synced `Place`s!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -750,17 +750,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"To make [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium)'s `Map` class work even better with our `Place` instances, we write our own `Map` class wrapping [folium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/python-visualization/folium)'s. Then, we add further functionality to the class throughout this tutorial.\n",
|
"To make [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium)'s `Map` class work even better with our `Place` instances, we write our own `Map` class wrapping [folium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/python-visualization/folium)'s. Then, we add further functionality to the class throughout this tutorial.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `.__init__()` method takes mandatory `name`, `center`, `start`, `end`, and `places` arguments. `name` is there for convenience, `center` is the map's initial center, `start` and `end` are `Place` instances, and `places` is a finite iterable of `Place` instances. Also, `.__init__()` accepts an optional `initial_zoom` argument defaulting to `12`.\n",
|
"The `__init__()` method takes mandatory `name`, `center`, `start`, `end`, and `places` arguments. `name` is there for convenience, `center` is the map's initial center, `start` and `end` are `Place` instances, and `places` is a finite iterable of `Place` instances. Also, `__init__()` accepts an optional `initial_zoom` argument defaulting to `12`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Upon initialization, a `folium.Map` instance is created and stored as an implementation detail `_map`. Also, `.__init__()` puts markers for each place on the `_map` object: `\"green\"` and `\"red\"` markers for the `start` and `end` locations and `\"blue\"` ones for the `places` to be visited. To do that, `.__init__()` invokes another `.add_marker()` method on the `Map` class, once for every `Place` object. `.add_marker()` itself invokes the `.add_to()` method on the `folium.Marker` representation of a `Place` instance and enables method chaining.\n",
|
"Upon initialization, a `folium.Map` instance is created and stored as an implementation detail `_map`. Also, `__init__()` puts markers for each place on the `_map` object: `\"green\"` and `\"red\"` markers for the `start` and `end` locations and `\"blue\"` ones for the `places` to be visited. To do that, `__init__()` invokes another `add_marker()` method on the `Map` class, once for every `Place` object. `add_marker()` itself invokes the `add_to()` method on the `folium.Marker` representation of a `Place` instance and enables method chaining.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"To keep the state in a `Map` instance consistent, all passed in arguments except `name` are treated as implementation details. Otherwise, a user of the `Map` class could, for example, change the `start` attribute, which would not be reflected in the internally kept `folium.Map` object.\n",
|
"To keep the state in a `Map` instance consistent, all passed in arguments except `name` are treated as implementation details. Otherwise, a user of the `Map` class could, for example, change the `start` attribute, which would not be reflected in the internally kept `folium.Map` object.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q23**: Implement the `.__init__()` and `.add_marker()` methods on the `Map` class as described!\n",
|
"**Q23**: Implement the `__init__()` and `add_marker()` methods on the `Map` class as described!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q24**: Add a `.show()` method on the `Map` class that simply returns the internal `folium.Map` object!"
|
"**Q24**: Add a `show()` method on the `Map` class that simply returns the internal `folium.Map` object!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -820,7 +820,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Let's put all the sights, the two airports, and three more places, the [Bundeskanzleramt <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/German_Chancellery), the [Olympic Stadium <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Olympiastadion_%28Berlin%29), and the [East Side Gallery <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/East_Side_Gallery), on the map.\n",
|
"Let's put all the sights, the two airports, and three more places, the [Bundeskanzleramt <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/German_Chancellery), the [Olympic Stadium <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Olympiastadion_%28Berlin%29), and the [East Side Gallery <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/East_Side_Gallery), on the map.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q25**: Execute the next code cells to create a map of Berlin with all the places on it!\n",
|
"**Q25**: Execute the next code cells to create a map of Berlin with all the places on it!\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -889,9 +889,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Before we can find out the best order in which to visit all the sights, we must calculate the pairwise distances between all points. While Google also offers a [Directions API](https://developers.google.com/maps/documentation/directions/start) and a [Distance Matrix API](https://developers.google.com/maps/documentation/distance-matrix/start), we choose to calculate the air distances using the third-party library [geopy <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/geopy/geopy).\n",
|
"Before we can find out the best order in which to visit all the sights, we must calculate the pairwise distances between all points. While Google also offers a [Directions API](https://developers.google.com/maps/documentation/directions/start) and a [Distance Matrix API](https://developers.google.com/maps/documentation/distance-matrix/start), we choose to calculate the air distances using the third-party library [geopy <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/geopy/geopy).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q26**: Familiarize yourself with the [documentation](https://geopy.readthedocs.io/en/stable/) and install [geopy <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/geopy/geopy) with the `pip` command line tool!"
|
"**Q26**: Familiarize yourself with the [documentation](https://geopy.readthedocs.io/en/stable/) and install [geopy <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/geopy/geopy) with the `pip` command line tool!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -907,9 +907,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"We use [geopy <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/geopy/geopy) primarily for converting the `latitude`-`longitude` coordinates into a [distance matrix <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Distance_matrix).\n",
|
"We use [geopy <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/geopy/geopy) primarily for converting the `latitude`-`longitude` coordinates into a [distance matrix <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Distance_matrix).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Because the [earth is not flat <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Flat_Earth), [geopy <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_gh.png\">](https://github.com/geopy/geopy) provides a `great_circle()` function that calculates the so-called [orthodromic distance <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Great-circle_distance) between two places on a sphere."
|
"Because the [earth is not flat <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Flat_Earth), [geopy <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_gh.png\">](https://github.com/geopy/geopy) provides a `great_circle()` function that calculates the so-called [orthodromic distance <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Great-circle_distance) between two places on a sphere."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1084,9 +1084,9 @@
|
||||||
"source": [
|
"source": [
|
||||||
"Now, we add a read-only `distances` property on our `Map` class. As we are working with air distances, these are *symmetric* which reduces the number of distances we must calculate.\n",
|
"Now, we add a read-only `distances` property on our `Map` class. As we are working with air distances, these are *symmetric* which reduces the number of distances we must calculate.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"To do so, we use the [combinations() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.combinations) generator function in the [itertools <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html). That produces all possible `r`-`tuple`s from an `iterable` argument. `r` is `2` in our case as we are looking at `origin`-`destination` pairs.\n",
|
"To do so, we use the [combinations() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.combinations) generator function in the [itertools <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html). That produces all possible `r`-`tuple`s from an `iterable` argument. `r` is `2` in our case as we are looking at `origin`-`destination` pairs.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Let's first look at an easy example of [combinations() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.combinations) to understand how it works: It gives us all the `2`-`tuple`s from a `list` of five `numbers` disregarding the order of the `tuple`s' elements."
|
"Let's first look at an easy example of [combinations() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.combinations) to understand how it works: It gives us all the `2`-`tuple`s from a `list` of five `numbers` disregarding the order of the `tuple`s' elements."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1114,9 +1114,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"`distances` uses the internal `._start`, `._end`, and `._places` attributes and creates a `dict` with the keys consisting of all pairs of `Place`s and the values being their distances in meters. As this operation is rather costly, we cache the distances the first time we calculate them into a hidden instance attribute `._distances`, which must be initialized with `None` in the `.__init__()` method.\n",
|
"`distances` uses the internal `_start`, `_end`, and `_places` attributes and creates a `dict` with the keys consisting of all pairs of `Place`s and the values being their distances in meters. As this operation is rather costly, we cache the distances the first time we calculate them into a hidden instance attribute `_distances`, which must be initialized with `None` in the `__init__()` method.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q31**: Finish the `.distances` property as described!"
|
"**Q31**: Finish the `distances` property as described!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1223,11 +1223,11 @@
|
||||||
"source": [
|
"source": [
|
||||||
"Let us find the cost minimal order of traveling from the `arrival` airport to the `departure` airport while visiting all the `sights`.\n",
|
"Let us find the cost minimal order of traveling from the `arrival` airport to the `departure` airport while visiting all the `sights`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This problem can be expressed as finding the shortest so-called [Hamiltonian path <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Hamiltonian_path) from the `start` to `end` on the `Map` (i.e., a path that visits each intermediate node exactly once). With the \"hack\" of assuming the distance of traveling from the `end` to the `start` to be `0` and thereby effectively merging the two airports into a single node, the problem can be viewed as a so-called [traveling salesman problem <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Traveling_salesman_problem) (TSP).\n",
|
"This problem can be expressed as finding the shortest so-called [Hamiltonian path <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Hamiltonian_path) from the `start` to `end` on the `Map` (i.e., a path that visits each intermediate node exactly once). With the \"hack\" of assuming the distance of traveling from the `end` to the `start` to be `0` and thereby effectively merging the two airports into a single node, the problem can be viewed as a so-called [traveling salesman problem <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Traveling_salesman_problem) (TSP).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The TSP is a hard problem to solve but also well studied in the literature. Assuming symmetric distances, a TSP with $n$ nodes has $\\frac{(n-1)!}{2}$ possible routes. $(n-1)$ because any node can be the `start` / `end` and divided by $2$ as the problem is symmetric.\n",
|
"The TSP is a hard problem to solve but also well studied in the literature. Assuming symmetric distances, a TSP with $n$ nodes has $\\frac{(n-1)!}{2}$ possible routes. $(n-1)$ because any node can be the `start` / `end` and divided by $2$ as the problem is symmetric.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Starting with about $n = 20$, the TSP is almost impossible to solve exactly in a reasonable amount of time. Luckily, we do not have that many `sights` to visit, and so we use a [brute force <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Brute-force_search) approach and simply loop over all possible routes to find the shortest.\n",
|
"Starting with about $n = 20$, the TSP is almost impossible to solve exactly in a reasonable amount of time. Luckily, we do not have that many `sights` to visit, and so we use a [brute force <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Brute-force_search) approach and simply loop over all possible routes to find the shortest.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In the case of our tourist, we \"only\" need to try out `181_440` possible routes because the two airports are effectively one node and $n$ becomes $10$."
|
"In the case of our tourist, we \"only\" need to try out `181_440` possible routes because the two airports are effectively one node and $n$ becomes $10$."
|
||||||
]
|
]
|
||||||
|
|
@ -1254,9 +1254,9 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Analyzing the problem a bit further, all we need is a list of [permutations <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_wiki.png\">](https://en.wikipedia.org/wiki/Permutation) of the sights as the two airports are always the first and last location.\n",
|
"Analyzing the problem a bit further, all we need is a list of [permutations <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_wiki.png\">](https://en.wikipedia.org/wiki/Permutation) of the sights as the two airports are always the first and last location.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) generator function in the [itertools <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/index.html) helps us with the task. Let's see an example to understand how it works."
|
"The [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) generator function in the [itertools <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html) module in the [standard library <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/index.html) helps us with the task. Let's see an example to understand how it works."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1275,7 +1275,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"However, if we use [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) as is, we try out *redundant* routes. For example, transferred to our case, the tuples `(1, 2, 3)` and `(3, 2, 1)` represent the *same* route as the distances are symmetric and the tourist could be going in either direction. To obtain the *unique* routes, we use an `if`-clause in a \"hacky\" way by only accepting routes where the first node has a smaller value than the last. Thus, we keep, for example, `(1, 2, 3)` and discard `(3, 2, 1)`."
|
"However, if we use [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) as is, we try out *redundant* routes. For example, transferred to our case, the tuples `(1, 2, 3)` and `(3, 2, 1)` represent the *same* route as the distances are symmetric and the tourist could be going in either direction. To obtain the *unique* routes, we use an `if`-clause in a \"hacky\" way by only accepting routes where the first node has a smaller value than the last. Thus, we keep, for example, `(1, 2, 3)` and discard `(3, 2, 1)`."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1293,7 +1293,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In order to compare `Place`s as numbers, we would have to implement, among others, the `.__eq__()` special method. Otherwise, we get a `TypeError`."
|
"In order to compare `Place`s as numbers, we would have to implement, among others, the `__eq__()` special method. Otherwise, we get a `TypeError`."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1309,7 +1309,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"As a quick and dirty solution, we use the `.location` property on a `Place` to do the comparison."
|
"As a quick and dirty solution, we use the `location` property on a `Place` to do the comparison."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1325,7 +1325,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"As the code cell below shows, combining [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) with an `if`-clause results in the correct number of routes to be looped over."
|
"As the code cell below shows, combining [permutations() <img height=\"12\" style=\"display: inline-block\" src=\"static/link_to_py.png\">](https://docs.python.org/3/library/itertools.html#itertools.permutations) with an `if`-clause results in the correct number of routes to be looped over."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1347,13 +1347,13 @@
|
||||||
"source": [
|
"source": [
|
||||||
"To implement the brute force algorithm, we split the logic into two methods.\n",
|
"To implement the brute force algorithm, we split the logic into two methods.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"First, we create an `.evaluate()` method that takes a `route` argument that is a sequence of `Place`s and returns the total distance of the route. Internally, this method uses the `.distances` property repeatedly, which is why we built in caching above.\n",
|
"First, we create an `evaluate()` method that takes a `route` argument that is a sequence of `Place`s and returns the total distance of the route. Internally, this method uses the `distances` property repeatedly, which is why we built in caching above.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q32**: Finish the `.evaluate()` method as described!\n",
|
"**Q32**: Finish the `evaluate()` method as described!\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Second, we create a `.brute_force()` method that needs no arguments. It loops over all possible routes to find the shortest. As the `start` and `end` of a route are fixed, we only need to look at `permutation`s of inner nodes. Each `permutation` can then be traversed in a forward and a backward order. `.brute_force()` enables method chaining as well.\n",
|
"Second, we create a `brute_force()` method that needs no arguments. It loops over all possible routes to find the shortest. As the `start` and `end` of a route are fixed, we only need to look at `permutation`s of inner nodes. Each `permutation` can then be traversed in a forward and a backward order. `brute_force` enables method chaining as well.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Q33**: Finish the `.brute_force()` method as described!"
|
"**Q33**: Finish the `brute_force()` method as described!"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1476,7 +1476,7 @@
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.12.2"
|
"version": "3.7.4"
|
||||||
},
|
},
|
||||||
"toc": {
|
"toc": {
|
||||||
"base_numbering": 1,
|
"base_numbering": 1,
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,100 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "slide"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 11: Classes & Instances (TL;DR)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"slideshow": {
|
|
||||||
"slide_type": "skip"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"With the `class` statement, we can create a *user-defined* data type that we also call a **class**.\n",
|
|
||||||
"\n",
|
|
||||||
"Then, to create new **instances** of the data type, we simply call the class, just as we do with the built-in constructors.\n",
|
|
||||||
"\n",
|
|
||||||
"Conceptually, a class is the **blueprint** defining the **behavior** each instance exhibits.\n",
|
|
||||||
"\n",
|
|
||||||
"In the example used throughout the chapter, the `Vector` and `Matrix` classes implement the linear algebra rules all `Vector` and `Matrix` instances follow *in general*. On the contrary, the instances **encapsulate** the **state** of *concrete* vectors and matrices.\n",
|
|
||||||
"\n",
|
|
||||||
"The `class` statement acts as a *namespace* that consists of simple *variable assignments* and *function definitions*:\n",
|
|
||||||
"1. Variables become the **class attributes** that are shared among all instances.\n",
|
|
||||||
"2. Functions may take a different role:\n",
|
|
||||||
" - By default, they become **instance methods** by going through a **binding process** where a reference to the instance on which the method is *invoked* is passed in as the first argument. By convention, the corresponding parameter is called `self`; it embodies an instance's state: That means that instance methods set and get **instance attributes** on and from `self`.\n",
|
|
||||||
" - They may be declared as **class methods**. Then, the binding process is adjusted such that the first argument passed in is a reference to the class itself and, by convention, named `cls`. A common use case is to design **alternative constructors**.\n",
|
|
||||||
" - They may also be declared as **properties**. A use case for that are *derived* attributes that follow semantically from an instance's state.\n",
|
|
||||||
" \n",
|
|
||||||
"The **Python Data Model** concerns what special methods (i.e., the ones with the dunder names) exists and how they work together.\n",
|
|
||||||
"\n",
|
|
||||||
"The instantiation process is controlled by the `.__init__()` method.\n",
|
|
||||||
"\n",
|
|
||||||
"The `__repr__()` and `__str__()` methods implement the **text representation** of an instance, which can be regarded as a Unicode encoded representation of all the state encapsulated in an instance.\n",
|
|
||||||
"\n",
|
|
||||||
"**Sequence emulation** means that a user-defined data type exhibits the same four properties as the built-in sequences, which are regarded as finite and iterable containers with a predictable order. The `.__len__()`, `.__iter__()`, `__reversed__()`, `__getitem__()`, and some others are used to implement the corresponding behaviors.\n",
|
|
||||||
"\n",
|
|
||||||
"Similarly, **number emulation** means that an instance of a user-defined data type behaves like a built-in number. For example, by implementing the `.__abs__()` method, an instance may be passed to the built-in [abs() <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_py.png\">](https://docs.python.org/3/library/functions.html#abs) function.\n",
|
|
||||||
"\n",
|
|
||||||
"If different data types, built-in or user-defined, share a well-defined set of behaviors, a single function may be written to work with objects of all the data types. We describe such functions as **polymorphic**.\n",
|
|
||||||
"\n",
|
|
||||||
"Classes may specify how *operators* are **overloaded**. Examples for that are the `.__add__()`, `.__sub__()`, or `.__eq__()` methods.\n",
|
|
||||||
"\n",
|
|
||||||
"**Packages** are folders containing **modules** (i.e., \\*.py files) and a \"*\\_\\_init\\_\\_.py*\" file. We use them to design coherent libraries with reusable code."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"livereveal": {
|
|
||||||
"auto_select": "code",
|
|
||||||
"auto_select_fragment": true,
|
|
||||||
"scroll": true,
|
|
||||||
"theme": "serif"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {
|
|
||||||
"height": "calc(100% - 180px)",
|
|
||||||
"left": "10px",
|
|
||||||
"top": "150px",
|
|
||||||
"width": "384px"
|
|
||||||
},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,271 +0,0 @@
|
||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Chapter 11: Classes & Instances (Review Questions)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The questions below assume that you have read the [first <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb), [second <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/02_content.ipynb), [third <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/03_content.ipynb), and [fourth <img height=\"12\" style=\"display: inline-block\" src=\"../static/link/to_nb.png\">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/04_content.ipynb) part of Chapter 11.\n",
|
|
||||||
"\n",
|
|
||||||
"Be concise in your answers! Most questions can be answered in *one* sentence."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Essay Questions "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q1**: How are **classes** a way to manage the **state** in a big program? How should we think of classes conceptually?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q2**: What do we mean with **instantiation**? How do **instances** relate to **classes**?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q3:** What is an **implementation detail**? Name two different examples of implementation details regarding the `Vector` and `Matrix` classes!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q4**: How are **instance methods** different from **class methods**? How do **special methods** fit into the picture?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q5**: How do **mutability** and **immutability** come into play when designing a user-defined data type?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q6**: Explain the concept of **method chaining**!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q7**: How can we implement **operator overloading** for a user-defined data type? When do we need to user *reverse* special methods?"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## True / False Questions"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Motivate your answer with *one short* sentence!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q8**: An instance's **text representation** is a `bytes` object with a special encoding."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q9**: Computed **properties** are special kinds of **instance methods**."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q10**: **Sequence emulation** means designing a user-defined data type around the built-in `list` or `tuple` types."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q11**: The **Python Data Model** can be regarded as the \"Theory\" or \"Mental Model\" behind the Python language."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q12**: **Polymorphism** means that two instances have the same data type, be it a built-in or user-defined one."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q13**: **Number emulation** means that two instances of the same user-defined data type can be added together."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**Q14**: **Packages** are a good place to collect all the code to be reused in a data science project, for example, across different Jupyter notebooks."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
" < your answer >"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.2"
|
|
||||||
},
|
|
||||||
"toc": {
|
|
||||||
"base_numbering": 1,
|
|
||||||
"nav_menu": {},
|
|
||||||
"number_sections": false,
|
|
||||||
"sideBar": true,
|
|
||||||
"skip_h1_title": true,
|
|
||||||
"title_cell": "Table of Contents",
|
|
||||||
"title_sidebar": "Contents",
|
|
||||||
"toc_cell": false,
|
|
||||||
"toc_position": {},
|
|
||||||
"toc_section_display": false,
|
|
||||||
"toc_window_display": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
"""This package provides linear algebra functionalities.
|
|
||||||
|
|
||||||
The package is split into three modules:
|
|
||||||
- matrix: defines the Matrix class
|
|
||||||
- vector: defines the Vector class
|
|
||||||
- utils: defines the norm() function that is shared by Matrix and Vector
|
|
||||||
and package-wide constants
|
|
||||||
|
|
||||||
The classes implement arithmetic operations involving vectors and matrices.
|
|
||||||
|
|
||||||
See the docstrings in the modules and classes for further info.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Import the classes here so that they are available
|
|
||||||
# from the package's top level. That means that a user
|
|
||||||
# who imports this package with `import sample_package`
|
|
||||||
# may then refer to, for example, the Matrix class with
|
|
||||||
# simply `sample_package.Matrix` instead of the longer
|
|
||||||
# `sample_package.matrix.Matrix`.
|
|
||||||
from sample_package.matrix import Matrix
|
|
||||||
from sample_package.vector import Vector
|
|
||||||
|
|
||||||
|
|
||||||
# Define meta information for the package.
|
|
||||||
# There are other (and more modern) ways of
|
|
||||||
# doing this, but specifying the following
|
|
||||||
# dunder variables here is the traditional way.
|
|
||||||
__name__ = "linear_algebra_tools"
|
|
||||||
__version__ = "0.1.0" # see https://semver.org/ for how the format works
|
|
||||||
__author__ = "Alexander Hess"
|
|
||||||
|
|
||||||
# Define what is imported with the "star import"
|
|
||||||
# (i.e., with `from sample_package import *`).
|
|
||||||
__all__ = ["Matrix", "Vector"]
|
|
||||||
|
|
@ -1,443 +0,0 @@
|
||||||
"""This module defines a Matrix class."""
|
|
||||||
|
|
||||||
import numbers
|
|
||||||
|
|
||||||
# Note the import at the bottom of this file, and
|
|
||||||
# see the comments about imports in the matrix module.
|
|
||||||
from sample_package import utils
|
|
||||||
|
|
||||||
|
|
||||||
class Matrix:
|
|
||||||
"""An m-by-n-dimensional matrix from linear algebra.
|
|
||||||
|
|
||||||
All entries are converted to floats, or whatever is set in the typing attribute.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
storage (callable): data type used to store the entries internally;
|
|
||||||
defaults to tuple
|
|
||||||
typing (callable): type casting applied to all entries upon creation;
|
|
||||||
defaults to float
|
|
||||||
vector_cls (vector.Vector): a reference to the Vector class to work with
|
|
||||||
zero_threshold (float): max. tolerance when comparing an entry to zero;
|
|
||||||
defaults to 1e-12
|
|
||||||
"""
|
|
||||||
|
|
||||||
storage = utils.DEFAULT_ENTRIES_STORAGE
|
|
||||||
typing = utils.DEFAULT_ENTRY_TYPE
|
|
||||||
# the `vector_cls` attribute is set at the bottom of this file
|
|
||||||
zero_threshold = utils.ZERO_THRESHOLD
|
|
||||||
|
|
||||||
def __init__(self, data):
|
|
||||||
"""Create a new matrix.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (sequence of sequences): the matrix's entries;
|
|
||||||
viewed as a sequence of the matrix's rows (i.e., row-major order);
|
|
||||||
use the .from_columns() class method if the data come as a sequence
|
|
||||||
of the matrix's columns (i.e., column-major order)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError:
|
|
||||||
- if no entries are provided
|
|
||||||
- if the number of columns is inconsistent across the rows
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((1.0, 2.0,), (3.0, 4.0,)))
|
|
||||||
"""
|
|
||||||
self._entries = self.storage(
|
|
||||||
self.storage(self.typing(x) for x in r) for r in data
|
|
||||||
)
|
|
||||||
for row in self._entries[1:]:
|
|
||||||
if len(row) != self.n_cols:
|
|
||||||
raise ValueError("rows must have the same number of entries")
|
|
||||||
if len(self) == 0:
|
|
||||||
raise ValueError("a matrix must have at least one entry")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_columns(cls, data):
|
|
||||||
"""Create a new matrix.
|
|
||||||
|
|
||||||
This is an alternative constructor for data provided in column-major order.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (sequence of sequences): the matrix's entries;
|
|
||||||
viewed as a sequence of the matrix's columns (i.e., column-major order);
|
|
||||||
use the normal constructor method if the data come as a sequence
|
|
||||||
of the matrix's rows (i.e., row-major order)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError:
|
|
||||||
- if no entries are provided
|
|
||||||
- if the number of rows is inconsistent across the columns
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix.from_columns([(1, 2), (3, 4)])
|
|
||||||
Matrix(((1.0, 3.0,), (2.0, 4.0,)))
|
|
||||||
"""
|
|
||||||
return cls(data).transpose()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_rows(cls, data):
|
|
||||||
"""See docstring for .__init__()."""
|
|
||||||
# Some users may want to use this .from_rows() constructor
|
|
||||||
# to explicitly communicate that the data are in row-major order.
|
|
||||||
# Otherwise, this method is redundant.
|
|
||||||
return cls(data)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Text representation of a Matrix."""
|
|
||||||
name = self.__class__.__name__
|
|
||||||
args = ", ".join(
|
|
||||||
"(" + ", ".join(repr(c) for c in r) + ",)" for r in self._entries
|
|
||||||
)
|
|
||||||
return f"{name}(({args}))"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Human-readable text representation of a Matrix."""
|
|
||||||
name = self.__class__.__name__
|
|
||||||
first, last, m, n = self[0], self[-1], self.n_rows, self.n_cols
|
|
||||||
return f"{name}(({first!r}, ...), ..., (..., {last!r}))[{m:d}x{n:d}]"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def n_rows(self):
|
|
||||||
"""Number of rows in a Matrix."""
|
|
||||||
return len(self._entries)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def n_cols(self):
|
|
||||||
"""Number of columns in a Matrix."""
|
|
||||||
return len(self._entries[0])
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
"""Number of entries in a Matrix."""
|
|
||||||
return self.n_rows * self.n_cols
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
"""Obtain an individual entry of a Matrix.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
index (int / tuple of int's): if index is an integer,
|
|
||||||
the Matrix is viewed as a sequence in row-major order;
|
|
||||||
if index is a tuple of integers, the first one refers to
|
|
||||||
the row and the second one to the column of the entry
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
entry (Matrix.typing)
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> m = Matrix([(1, 2), (3, 4)])
|
|
||||||
>>> m[0]
|
|
||||||
1.0
|
|
||||||
>>> m[-1]
|
|
||||||
4.0
|
|
||||||
>>> m[0, 1]
|
|
||||||
2.0
|
|
||||||
"""
|
|
||||||
# Sequence-like indexing (one-dimensional)
|
|
||||||
if isinstance(index, int):
|
|
||||||
if index < 0:
|
|
||||||
index += len(self)
|
|
||||||
if not (0 <= index < len(self)):
|
|
||||||
raise IndexError("integer index out of range")
|
|
||||||
row, col = divmod(index, self.n_cols)
|
|
||||||
return self._entries[row][col]
|
|
||||||
# Mathematical-like indexing (two-dimensional)
|
|
||||||
elif (
|
|
||||||
isinstance(index, tuple)
|
|
||||||
and len(index) == 2
|
|
||||||
and isinstance(index[0], int)
|
|
||||||
and isinstance(index[1], int)
|
|
||||||
):
|
|
||||||
return self._entries[index[0]][index[1]]
|
|
||||||
raise TypeError("index must be either an int or a tuple of two int's")
|
|
||||||
|
|
||||||
def rows(self):
|
|
||||||
"""Loop over a Matrix's rows.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
rows (generator): produces a Matrix's rows as Vectors
|
|
||||||
"""
|
|
||||||
return (self.vector_cls(r) for r in self._entries)
|
|
||||||
|
|
||||||
def cols(self):
|
|
||||||
"""Loop over a Matrix's columns.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
columns (generator): produces a Matrix's columns as Vectors
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
self.vector_cls(self._entries[r][c] for r in range(self.n_rows))
|
|
||||||
for c in range(self.n_cols)
|
|
||||||
)
|
|
||||||
|
|
||||||
def entries(self, *, reverse=False, row_major=True):
|
|
||||||
"""Loop over a Matrix's entries.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
reverse (bool): flag to loop backwards; defaults to False
|
|
||||||
row_major (bool): flag to loop in row-major order; defaults to True
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
entries (generator): produces a Matrix's entries
|
|
||||||
"""
|
|
||||||
if reverse:
|
|
||||||
rows = range(self.n_rows - 1, -1, -1)
|
|
||||||
cols = range(self.n_cols - 1, -1, -1)
|
|
||||||
else:
|
|
||||||
rows, cols = range(self.n_rows), range(self.n_cols)
|
|
||||||
if row_major:
|
|
||||||
return (self._entries[r][c] for r in rows for c in cols)
|
|
||||||
return (self._entries[r][c] for c in cols for r in rows)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
"""Loop over a Matrix's entries.
|
|
||||||
|
|
||||||
See .entries() for more customization options.
|
|
||||||
"""
|
|
||||||
return self.entries()
|
|
||||||
|
|
||||||
def __reversed__(self):
|
|
||||||
"""Loop over a Matrix's entries in reverse order.
|
|
||||||
|
|
||||||
See .entries() for more customization options.
|
|
||||||
"""
|
|
||||||
return self.entries(reverse=True)
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
"""Handle `self + other` and `other + self`.
|
|
||||||
|
|
||||||
This may be either matrix addition or broadcasting addition.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) + Matrix([(2, 3), (4, 5)])
|
|
||||||
Matrix(((3.0, 5.0,), (7.0, 9.0,)))
|
|
||||||
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) + 5
|
|
||||||
Matrix(((6.0, 7.0,), (8.0, 9.0,)))
|
|
||||||
|
|
||||||
>>> 10 + Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((11.0, 12.0,), (13.0, 14.0,)))
|
|
||||||
"""
|
|
||||||
# Matrix addition
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols):
|
|
||||||
raise ValueError("matrices must have the same dimensions")
|
|
||||||
return self.__class__(
|
|
||||||
(s_col + o_col for (s_col, o_col) in zip(s_row, o_row))
|
|
||||||
for (s_row, o_row) in zip(self._entries, other._entries)
|
|
||||||
)
|
|
||||||
# Broadcasting addition
|
|
||||||
elif isinstance(other, numbers.Number):
|
|
||||||
return self.__class__((c + other for c in r) for r in self._entries)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __radd__(self, other):
|
|
||||||
"""See docstring for .__add__()."""
|
|
||||||
if isinstance(other, self.vector_cls):
|
|
||||||
raise TypeError("vectors and matrices cannot be added")
|
|
||||||
# As both matrix and broadcasting addition are commutative,
|
|
||||||
# we dispatch to .__add__().
|
|
||||||
return self + other
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
"""Handle `self - other` and `other - self`.
|
|
||||||
|
|
||||||
This may be either matrix subtraction or broadcasting subtraction.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(2, 3), (4, 5)]) - Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((1.0, 1.0,), (1.0, 1.0,)))
|
|
||||||
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) - 1
|
|
||||||
Matrix(((0.0, 1.0,), (2.0, 3.0,)))
|
|
||||||
|
|
||||||
>>> 10 - Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((9.0, 8.0,), (7.0, 6.0,)))
|
|
||||||
"""
|
|
||||||
# As subtraction is the inverse of addition,
|
|
||||||
# we first dispatch to .__neg__() to invert the signs of
|
|
||||||
# all entries in other and then dispatch to .__add__().
|
|
||||||
return self + (-other)
|
|
||||||
|
|
||||||
def __rsub__(self, other):
|
|
||||||
"""See docstring for .__sub__()."""
|
|
||||||
if isinstance(other, self.vector_cls):
|
|
||||||
raise TypeError("vectors and matrices cannot be subtracted")
|
|
||||||
# Same comments as in .__sub__() apply
|
|
||||||
# with the roles of self and other swapped.
|
|
||||||
return (-self) + other
|
|
||||||
|
|
||||||
def _matrix_multiply(self, other):
|
|
||||||
"""Internal utility method to multiply to Matrix instances."""
|
|
||||||
if self.n_cols != other.n_rows:
|
|
||||||
raise ValueError("matrices must have compatible dimensions")
|
|
||||||
# Matrix-matrix multiplication means that each entry of the resulting
|
|
||||||
# Matrix is the dot product of the respective row of the "left" Matrix
|
|
||||||
# and column of the "right" Matrix. So, the rows/columns are represented
|
|
||||||
# by the Vector instances provided by the .cols() and .rows() methods.
|
|
||||||
return self.__class__((rv * cv for cv in other.cols()) for rv in self.rows())
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
"""Handle `self * other` and `other * self`.
|
|
||||||
|
|
||||||
This may be either scalar multiplication, matrix-vector multiplication,
|
|
||||||
vector-matrix multiplication, or matrix-matrix multiplication.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) * Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((7.0, 10.0,), (15.0, 22.0,)))
|
|
||||||
|
|
||||||
>>> 2 * Matrix([(1, 2), (3, 4)])
|
|
||||||
Matrix(((2.0, 4.0,), (6.0, 8.0,)))
|
|
||||||
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) * 3
|
|
||||||
Matrix(((3.0, 6.0,), (9.0, 12.0,)))
|
|
||||||
|
|
||||||
Matrix-vector and vector-matrix multiplication are not commutative.
|
|
||||||
|
|
||||||
>>> from sample_package import Vector
|
|
||||||
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) * Vector([5, 6])
|
|
||||||
Vector((17.0, 39.0))
|
|
||||||
|
|
||||||
>>> Vector([5, 6]) * Matrix([(1, 2), (3, 4)])
|
|
||||||
Vector((23.0, 34.0))
|
|
||||||
"""
|
|
||||||
# Scalar multiplication
|
|
||||||
if isinstance(other, numbers.Number):
|
|
||||||
return self.__class__((x * other for x in r) for r in self._entries)
|
|
||||||
# Matrix-vector multiplication: Vector is a column Vector
|
|
||||||
elif isinstance(other, self.vector_cls):
|
|
||||||
# First, cast the other Vector as a Matrix, then do matrix-matrix
|
|
||||||
# multiplication, and lastly return the result as a Vector again.
|
|
||||||
return self._matrix_multiply(other.as_matrix()).as_vector()
|
|
||||||
# Matrix-matrix multiplication
|
|
||||||
elif isinstance(other, self.__class__):
|
|
||||||
return self._matrix_multiply(other)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __rmul__(self, other):
|
|
||||||
"""See docstring for .__mul__()."""
|
|
||||||
# As scalar multiplication is commutative, we dispatch to .__mul__().
|
|
||||||
if isinstance(other, numbers.Number):
|
|
||||||
return self * other
|
|
||||||
# Vector-matrix multiplication: Vector is a row Vector
|
|
||||||
elif isinstance(other, self.vector_cls):
|
|
||||||
return other.as_matrix(column=False)._matrix_multiply(self).as_vector()
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __truediv__(self, other):
|
|
||||||
"""Handle `self / other`.
|
|
||||||
|
|
||||||
Divide a Matrix by a scalar.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) / 4
|
|
||||||
Matrix(((0.25, 0.5,), (0.75, 1.0,)))
|
|
||||||
"""
|
|
||||||
# As scalar division division is the same as multiplication
|
|
||||||
# with the inverse, we dispatch to .__mul__().
|
|
||||||
if isinstance(other, numbers.Number):
|
|
||||||
return self * (1 / other)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
"""Handle `self == other`.
|
|
||||||
|
|
||||||
Compare two Matrix instances for equality.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) == Matrix([(1, 2), (3, 4)])
|
|
||||||
True
|
|
||||||
|
|
||||||
>>> Matrix([(1, 2), (3, 4)]) == Matrix([(5, 6), (7, 8)])
|
|
||||||
False
|
|
||||||
"""
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if (self.n_rows != other.n_rows) or (self.n_cols != other.n_cols):
|
|
||||||
raise ValueError("matrices must have the same dimensions")
|
|
||||||
for x, y in zip(self, other):
|
|
||||||
if abs(x - y) > self.zero_threshold:
|
|
||||||
return False # exit early if two corresponding entries differ
|
|
||||||
return True
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __pos__(self):
|
|
||||||
"""Handle `+self`.
|
|
||||||
|
|
||||||
This is simply an identity operator returning the Matrix itself.
|
|
||||||
"""
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __neg__(self):
|
|
||||||
"""Handle `-self`.
|
|
||||||
|
|
||||||
Negate all entries of a Matrix.
|
|
||||||
"""
|
|
||||||
return self.__class__((-x for x in r) for r in self._entries)
|
|
||||||
|
|
||||||
def __abs__(self):
|
|
||||||
"""The Frobenius norm of a Matrix."""
|
|
||||||
return utils.norm(self) # uses the norm() function shared vector.Vector
|
|
||||||
|
|
||||||
def __bool__(self):
|
|
||||||
"""A Matrix is truthy if its Frobenius norm is strictly positive."""
|
|
||||||
return bool(abs(self))
|
|
||||||
|
|
||||||
def __float__(self):
|
|
||||||
"""Cast a Matrix as a scalar.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
scalar (float)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: if the Matrix has more than one entry
|
|
||||||
"""
|
|
||||||
if not (self.n_rows == 1 and self.n_cols == 1):
|
|
||||||
raise RuntimeError("matrix must have exactly one entry to become a scalar")
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
def as_vector(self):
|
|
||||||
"""Get a Vector representation of a Matrix.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
vector (vector.Vector)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: if one of the two dimensions, .n_rows or .n_cols, is not 1
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Matrix([(1, 2, 3)]).as_vector()
|
|
||||||
Vector((1.0, 2.0, 3.0))
|
|
||||||
"""
|
|
||||||
if not (self.n_rows == 1 or self.n_cols == 1):
|
|
||||||
raise RuntimeError("one dimension (m or n) must be 1")
|
|
||||||
return self.vector_cls(x for x in self)
|
|
||||||
|
|
||||||
def transpose(self):
|
|
||||||
"""Switch the rows and columns of a Matrix.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
matrix (Matrix)
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> m = Matrix([(1, 2), (3, 4)])
|
|
||||||
>>> m
|
|
||||||
Matrix(((1.0, 2.0,), (3.0, 4.0,)))
|
|
||||||
>>> m.transpose()
|
|
||||||
Matrix(((1.0, 3.0,), (2.0, 4.0,)))
|
|
||||||
"""
|
|
||||||
return self.__class__(zip(*self._entries))
|
|
||||||
|
|
||||||
|
|
||||||
# This import needs to be made here as otherwise an ImportError is raised.
|
|
||||||
# That is so as both the matrix and vector modules import a class from each other.
|
|
||||||
# We call that a circular import. Whereas Python handles "circular" references
|
|
||||||
# (e.g., both the Matrix and Vector classes have methods that reference the
|
|
||||||
# respective other class), that is forbidden for imports.
|
|
||||||
from sample_package import vector
|
|
||||||
|
|
||||||
# This attribute cannot be set in the class definition
|
|
||||||
# as the vector module is only imported down here.
|
|
||||||
Matrix.vector_cls = vector.Vector
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
"""This module provides utilities for the whole package.
|
|
||||||
|
|
||||||
The defined constants are used as defaults in the Vector and Matrix classes.
|
|
||||||
|
|
||||||
The norm() function is shared by Vector.__abs__() and Matrix.__abs__().
|
|
||||||
"""
|
|
||||||
|
|
||||||
import math
|
|
||||||
|
|
||||||
|
|
||||||
# Define constants (i.e., normal variables that are, by convention, named in UPPERCASE)
|
|
||||||
# that are used as the defaults for class attributes within Vector and Matrix.
|
|
||||||
DEFAULT_ENTRIES_STORAGE = tuple
|
|
||||||
DEFAULT_ENTRY_TYPE = float
|
|
||||||
ZERO_THRESHOLD = 1e-12
|
|
||||||
|
|
||||||
|
|
||||||
def norm(vec_or_mat):
|
|
||||||
"""Calculate the Frobenius or Euclidean norm of a matrix or vector.
|
|
||||||
|
|
||||||
Find more infos here: https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm
|
|
||||||
|
|
||||||
Args:
|
|
||||||
vec_or_mat (Vector / Matrix): object whose entries are squared and summed up
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
norm (float)
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
As Vector and Matrix objects are by design non-empty sequences,
|
|
||||||
norm() may be called, for example, with `[3, 4]` as the argument:
|
|
||||||
>>> norm([3, 4])
|
|
||||||
5.0
|
|
||||||
"""
|
|
||||||
return math.sqrt(sum(x ** 2 for x in vec_or_mat))
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
"""This module defines a Vector class."""
|
|
||||||
|
|
||||||
# Imports from the standard library go first ...
|
|
||||||
import numbers
|
|
||||||
|
|
||||||
# ... and are followed by project-internal ones.
|
|
||||||
# If third-party libraries are needed, they are
|
|
||||||
# put into a group on their own in between.
|
|
||||||
# Within a group, imports are sorted lexicographically.
|
|
||||||
from sample_package import matrix
|
|
||||||
from sample_package import utils
|
|
||||||
|
|
||||||
|
|
||||||
class Vector:
|
|
||||||
"""A one-dimensional vector from linear algebra.
|
|
||||||
|
|
||||||
All entries are converted to floats, or whatever is set in the typing attribute.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
matrix_cls (matrix.Matrix): a reference to the Matrix class to work with
|
|
||||||
storage (callable): data type used to store the entries internally;
|
|
||||||
defaults to tuple
|
|
||||||
typing (callable): type casting applied to all entries upon creation;
|
|
||||||
defaults to float
|
|
||||||
zero_threshold (float): max. tolerance when comparing an entry to zero;
|
|
||||||
defaults to 1e-12
|
|
||||||
"""
|
|
||||||
|
|
||||||
matrix_cls = matrix.Matrix
|
|
||||||
storage = utils.DEFAULT_ENTRIES_STORAGE
|
|
||||||
typing = utils.DEFAULT_ENTRY_TYPE
|
|
||||||
zero_threshold = utils.ZERO_THRESHOLD
|
|
||||||
|
|
||||||
def __init__(self, data):
|
|
||||||
"""Create a new vector.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data (sequence): the vector's entries
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: if no entries are provided
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([1, 2, 3])
|
|
||||||
Vector((1.0, 2.0, 3.0))
|
|
||||||
|
|
||||||
>>> Vector(range(3))
|
|
||||||
Vector((0.0, 1.0, 2.0))
|
|
||||||
"""
|
|
||||||
self._entries = self.storage(self.typing(x) for x in data)
|
|
||||||
if len(self) == 0:
|
|
||||||
raise ValueError("a vector must have at least one entry")
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Text representation of a Vector."""
|
|
||||||
name = self.__class__.__name__
|
|
||||||
args = ", ".join(repr(x) for x in self)
|
|
||||||
return f"{name}(({args}))"
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
"""Human-readable text representation of a Vector."""
|
|
||||||
name = self.__class__.__name__
|
|
||||||
first, last, n_entries = self[0], self[-1], len(self)
|
|
||||||
return f"{name}({first!r}, ..., {last!r})[{n_entries:d}]"
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
"""Number of entries in a Vector."""
|
|
||||||
return len(self._entries)
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
|
||||||
"""Obtain an individual entry of a Vector."""
|
|
||||||
if not isinstance(index, int):
|
|
||||||
raise TypeError("index must be an integer")
|
|
||||||
return self._entries[index]
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
"""Loop over a Vector's entries."""
|
|
||||||
return iter(self._entries)
|
|
||||||
|
|
||||||
def __reversed__(self):
|
|
||||||
"""Loop over a Vector's entries in reverse order."""
|
|
||||||
return reversed(self._entries)
|
|
||||||
|
|
||||||
def __add__(self, other):
|
|
||||||
"""Handle `self + other` and `other + self`.
|
|
||||||
|
|
||||||
This may be either vector addition or broadcasting addition.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([1, 2, 3]) + Vector([2, 3, 4])
|
|
||||||
Vector((3.0, 5.0, 7.0))
|
|
||||||
|
|
||||||
>>> Vector([1, 2, 3]) + 4
|
|
||||||
Vector((5.0, 6.0, 7.0))
|
|
||||||
|
|
||||||
>>> 10 + Vector([1, 2, 3])
|
|
||||||
Vector((11.0, 12.0, 13.0))
|
|
||||||
"""
|
|
||||||
# Vector addition
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if len(self) != len(other):
|
|
||||||
raise ValueError("vectors must be of the same length")
|
|
||||||
return self.__class__(x + y for (x, y) in zip(self, other))
|
|
||||||
# Broadcasting addition
|
|
||||||
elif isinstance(other, numbers.Number):
|
|
||||||
return self.__class__(x + other for x in self)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __radd__(self, other):
|
|
||||||
"""See docstring for .__add__()."""
|
|
||||||
# As both vector and broadcasting addition are commutative,
|
|
||||||
# we dispatch to .__add__().
|
|
||||||
return self + other
|
|
||||||
|
|
||||||
def __sub__(self, other):
|
|
||||||
"""Handle `self - other` and `other - self`.
|
|
||||||
|
|
||||||
This may be either vector subtraction or broadcasting subtraction.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([7, 8, 9]) - Vector([1, 2, 3])
|
|
||||||
Vector((6.0, 6.0, 6.0))
|
|
||||||
|
|
||||||
>>> Vector([1, 2, 3]) - 1
|
|
||||||
Vector((0.0, 1.0, 2.0))
|
|
||||||
|
|
||||||
>>> 10 - Vector([1, 2, 3])
|
|
||||||
Vector((9.0, 8.0, 7.0))
|
|
||||||
"""
|
|
||||||
# As subtraction is the inverse of addition,
|
|
||||||
# we first dispatch to .__neg__() to invert the signs of
|
|
||||||
# all entries in other and then dispatch to .__add__().
|
|
||||||
return self + (-other)
|
|
||||||
|
|
||||||
def __rsub__(self, other):
|
|
||||||
"""See docstring for .__sub__()."""
|
|
||||||
# Same comments as in .__sub__() apply
|
|
||||||
# with the roles of self and other swapped.
|
|
||||||
return (-self) + other
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
"""Handle `self * other` and `other * self`.
|
|
||||||
|
|
||||||
This may be either the dot product of two vectors or scalar multiplication.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([1, 2, 3]) * Vector([2, 3, 4])
|
|
||||||
20.0
|
|
||||||
|
|
||||||
>>> 2 * Vector([1, 2, 3])
|
|
||||||
Vector((2.0, 4.0, 6.0))
|
|
||||||
|
|
||||||
>>> Vector([1, 2, 3]) * 3
|
|
||||||
Vector((3.0, 6.0, 9.0))
|
|
||||||
"""
|
|
||||||
# Dot product
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if len(self) != len(other):
|
|
||||||
raise ValueError("vectors must be of the same length")
|
|
||||||
return sum(x * y for (x, y) in zip(self, other))
|
|
||||||
# Scalar multiplication
|
|
||||||
elif isinstance(other, numbers.Number):
|
|
||||||
return self.__class__(x * other for x in self)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __rmul__(self, other):
|
|
||||||
"""See docstring for .__mul__()."""
|
|
||||||
# As both dot product and scalar multiplication are commutative,
|
|
||||||
# we dispatch to .__mul__().
|
|
||||||
return self * other
|
|
||||||
|
|
||||||
def __truediv__(self, other):
|
|
||||||
"""Handle `self / other`.
|
|
||||||
|
|
||||||
Divide a Vector by a scalar.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([9, 6, 12]) / 3
|
|
||||||
Vector((3.0, 2.0, 4.0))
|
|
||||||
"""
|
|
||||||
# As scalar division division is the same as multiplication
|
|
||||||
# with the inverse, we dispatch to .__mul__().
|
|
||||||
if isinstance(other, numbers.Number):
|
|
||||||
return self * (1 / other)
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
"""Handle `self == other`.
|
|
||||||
|
|
||||||
Compare two Vectors for equality.
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> Vector([1, 2, 3]) == Vector([1, 2, 3])
|
|
||||||
True
|
|
||||||
|
|
||||||
>>> Vector([1, 2, 3]) == Vector([4, 5, 6])
|
|
||||||
False
|
|
||||||
"""
|
|
||||||
if isinstance(other, self.__class__):
|
|
||||||
if len(self) != len(other):
|
|
||||||
raise ValueError("vectors must be of the same length")
|
|
||||||
for x, y in zip(self, other):
|
|
||||||
if abs(x - y) > self.zero_threshold:
|
|
||||||
return False # exit early if two corresponding entries differ
|
|
||||||
return True
|
|
||||||
return NotImplemented
|
|
||||||
|
|
||||||
def __pos__(self):
|
|
||||||
"""Handle `+self`.
|
|
||||||
|
|
||||||
This is simply an identity operator returning the Vector itself.
|
|
||||||
"""
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __neg__(self):
|
|
||||||
"""Handle `-self`.
|
|
||||||
|
|
||||||
Negate all entries of a Vector.
|
|
||||||
"""
|
|
||||||
return self.__class__(-x for x in self)
|
|
||||||
|
|
||||||
def __abs__(self):
|
|
||||||
"""The Euclidean norm of a vector."""
|
|
||||||
return utils.norm(self) # uses the norm() function shared matrix.Matrix
|
|
||||||
|
|
||||||
def __bool__(self):
|
|
||||||
"""A Vector is truthy if its Euclidean norm is strictly positive."""
|
|
||||||
return bool(abs(self))
|
|
||||||
|
|
||||||
def __float__(self):
|
|
||||||
"""Cast a Vector as a scalar.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
scalar (float)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
RuntimeError: if the Vector has more than one entry
|
|
||||||
"""
|
|
||||||
if len(self) != 1:
|
|
||||||
raise RuntimeError("vector must have exactly one entry to become a scalar")
|
|
||||||
return self[0]
|
|
||||||
|
|
||||||
def as_matrix(self, *, column=True):
|
|
||||||
"""Get a Matrix representation of a Vector.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
column (bool): if the vector is interpreted as a
|
|
||||||
column vector or a row vector; defaults to True
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
matrix (matrix.Matrix)
|
|
||||||
|
|
||||||
Example Usage:
|
|
||||||
>>> v = Vector([1, 2, 3])
|
|
||||||
>>> v.as_matrix()
|
|
||||||
Matrix(((1.0,), (2.0,), (3.0,)))
|
|
||||||
>>> v.as_matrix(column=False)
|
|
||||||
Matrix(((1.0, 2.0, 3.0,)))
|
|
||||||
"""
|
|
||||||
if column:
|
|
||||||
return self.matrix_cls([x] for x in self)
|
|
||||||
return self.matrix_cls([(x for x in self)])
|
|
||||||
294
CONTENTS.md
294
CONTENTS.md
|
|
@ -1,294 +0,0 @@
|
||||||
# Table of Contents
|
|
||||||
|
|
||||||
The materials are designed to resemble an *interactive* book.
|
|
||||||
|
|
||||||
The files come
|
|
||||||
primarily in the [Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/stable/)
|
|
||||||
format (i.e., \*.ipynb)
|
|
||||||
but also as [modules and packages <img height="12" style="display: inline-block" src="static/link/to_py.png">](https://docs.python.org/3/tutorial/modules.html)
|
|
||||||
(i.e., \*.py).
|
|
||||||
Together with some other static files (e.g., images),
|
|
||||||
they are stored in one folder per chapter in this repository.
|
|
||||||
They are to be opened
|
|
||||||
from within the [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) application,
|
|
||||||
even though other ways are certainly possible as well.
|
|
||||||
Both the files and the folders
|
|
||||||
are appropriately named with prefixes
|
|
||||||
indicating the order in which they should be read
|
|
||||||
and starting with "00_".
|
|
||||||
|
|
||||||
It is recommended
|
|
||||||
to follow the [installation instructions](https://github.com/webartifex/intro-to-python#installation)
|
|
||||||
in the [README.md](README.md) file
|
|
||||||
and work through the content on one's own computer.
|
|
||||||
|
|
||||||
If this is not possible,
|
|
||||||
the files can be viewed in a web browser
|
|
||||||
either statically (i.e., read-only) on [nbviewer <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/tree/main/)
|
|
||||||
or interactively (i.e., code can be executed) on [Binder <img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab).
|
|
||||||
|
|
||||||
- *Chapter 0*: Introduction
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/00_intro/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/00_intro/00_content.ipynb)
|
|
||||||
(Python's History & Background;
|
|
||||||
Open-source & Communities;
|
|
||||||
JupyterLab;
|
|
||||||
Programming vs. Computer Science;
|
|
||||||
Learning Tips)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/00_intro/01_exercises_markdown.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/00_intro/01_exercises_markdown.ipynb)
|
|
||||||
(Mastering Markdown)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/00_intro/02_review.ipynb)
|
|
||||||
- **Part A: Expressing Logic**
|
|
||||||
- *Chapter 1*: Elements of a Program
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/00_content.ipynb)
|
|
||||||
(A first Example: Averaging Even Numbers;
|
|
||||||
Operators;
|
|
||||||
Objects & Data Types;
|
|
||||||
Errors)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/01_exercises_print.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/01_exercises_print.ipynb)
|
|
||||||
(Printing Output)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/02_exercises_for-loops.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/02_exercises_for-loops.ipynb)
|
|
||||||
(Simple `for`-loops)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/03_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/03_content.ipynb)
|
|
||||||
(Memory in Detail;
|
|
||||||
Variables & References;
|
|
||||||
Mutability;
|
|
||||||
Expressions & Statements)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/04_exercises_calculator.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/04_exercises_calculator.ipynb)
|
|
||||||
(Python as a Calculator)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/05_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/06_review.ipynb)
|
|
||||||
- [further resources <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/01_elements/07_resources.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/01_elements/07_resources.ipynb)
|
|
||||||
- *Chapter 2*: Functions & Modularization
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/02_functions/00_content.ipynb)
|
|
||||||
(Built-in Functions & Constructors;
|
|
||||||
Function Definitions;
|
|
||||||
Function Calls & Scoping Rules;
|
|
||||||
Positional vs. Keyword Arguments;
|
|
||||||
Modularization)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/01_exercises_sphere-volume.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/02_functions/01_exercises_sphere-volume.ipynb)
|
|
||||||
(Volume of a Sphere)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/02_functions/02_content.ipynb)
|
|
||||||
(Standard Library: `math` & `random` Modules;
|
|
||||||
Third-party Packages: `numpy` Library;
|
|
||||||
Writing one's own Modules)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/03_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/02_functions/04_review.ipynb)
|
|
||||||
- *Chapter 3*: Conditionals & Exceptions
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/03_conditionals/00_content.ipynb)
|
|
||||||
(Boolean Expressions;
|
|
||||||
Relational Operators;
|
|
||||||
Logical Operators;
|
|
||||||
`if` statement;
|
|
||||||
Exception Handling)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/01_exercises_discounts.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/03_conditionals/01_exercises_discounts.ipynb)
|
|
||||||
(Discounting Customer Orders)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/02_exercises_fizz-buzz.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/03_conditionals/02_exercises_fizz-buzz.ipynb)
|
|
||||||
(Fizz Buzz)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/03_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/03_conditionals/04_review.ipynb)
|
|
||||||
- *Chapter 4*: Recursion & Looping
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/00_content.ipynb)
|
|
||||||
(Recursion;
|
|
||||||
Examples: Factorial, Euclid's Algorithm, & Fibonacci;
|
|
||||||
Duck Typing;
|
|
||||||
Type Casting & Checking;
|
|
||||||
Input Validation)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/01_exercises_hanoi-towers.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/01_exercises_hanoi-towers.ipynb)
|
|
||||||
(Towers of Hanoi)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/02_content.ipynb)
|
|
||||||
(Looping with `while` & `for`;
|
|
||||||
Examples: Collatz Conjecture, Factorial, Euclid's Algorithm, & Fibonacci;
|
|
||||||
Containers vs. Iterables)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/03_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/03_content.ipynb)
|
|
||||||
(Customizing Loops with `break` and `continue`;
|
|
||||||
Indefinite Loops)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/04_exercises_dice.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/04_iteration/04_exercises_dice.ipynb)
|
|
||||||
(Throwing Dice)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/05_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/04_iteration/06_review.ipynb)
|
|
||||||
- **Part B: Managing Data and Memory**
|
|
||||||
- *Chapter 5*: Numbers & Bits
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/05_numbers/00_content.ipynb)
|
|
||||||
(`int` Type;
|
|
||||||
Binary & Hexadecimal Representations;
|
|
||||||
Bit Arithmetic;
|
|
||||||
Bitwise Operators)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/01_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/05_numbers/01_content.ipynb)
|
|
||||||
(`float` Type;
|
|
||||||
Floating-point Standard;
|
|
||||||
Special Values;
|
|
||||||
Imprecision;
|
|
||||||
Binary & Hexadecimal Representations)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/05_numbers/02_content.ipynb)
|
|
||||||
(`complex` Type;
|
|
||||||
Numerical Tower;
|
|
||||||
Duck vs. Goose Typing)
|
|
||||||
- [appendix <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/03_appendix.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/05_numbers/03_appendix.ipynb)
|
|
||||||
(`Decimal` Type;
|
|
||||||
`Fraction` Type)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/04_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/05_review.ipynb)
|
|
||||||
- [further resources <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/05_numbers/06_resources.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/05_numbers/06_resources.ipynb)
|
|
||||||
- *Chapter 6*: Text & Bytes
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/06_text/00_content.ipynb)
|
|
||||||
(`str` Type;
|
|
||||||
Reading Files;
|
|
||||||
Sequences;
|
|
||||||
Indexing & Slicing;
|
|
||||||
String Methods & Operations;
|
|
||||||
String Interpolation)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/01_exercises_palindromes.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/06_text/01_exercises_palindromes.ipynb)
|
|
||||||
(Detecting Palindromes)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/06_text/02_content.ipynb)
|
|
||||||
(Special Characters;
|
|
||||||
ASCII & Unicode;
|
|
||||||
Multi-line Strings;
|
|
||||||
`bytes` Type;
|
|
||||||
Character Encodings)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/03_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/04_review.ipynb)
|
|
||||||
- [further resources <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/06_text/05_resources.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/06_text/05_resources.ipynb)
|
|
||||||
- *Chapter 7*: Sequential Data
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/00_content.ipynb)
|
|
||||||
(Collections vs. Sequences;
|
|
||||||
ABCs: `Container`, `Iterable`, `Sized`, & `Reversible`)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/01_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/01_content.ipynb)
|
|
||||||
(`list` Type;
|
|
||||||
Indexing & Slicing;
|
|
||||||
Shallow vs. Deep Copies;
|
|
||||||
List Methods & Operations)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/02_exercises_lists.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/02_exercises_lists.ipynb)
|
|
||||||
(Working with Lists)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/03_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/03_content.ipynb)
|
|
||||||
(Modifiers vs. Pure Functions;
|
|
||||||
`tuple` Type;
|
|
||||||
Packing & Unpacking;
|
|
||||||
`*args` in Function Definitions)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/04_exercises_un-packing.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/04_exercises_un-packing.ipynb)
|
|
||||||
(Packing & Unpacking with Functions)
|
|
||||||
- [appendix <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/05_appendix.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/07_sequences/05_appendix.ipynb)
|
|
||||||
(`namedtuple` Type)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/06_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/07_sequences/07_review.ipynb)
|
|
||||||
- *Chapter 8*: Map, Filter, & Reduce
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/00_content.ipynb)
|
|
||||||
(Mapping;
|
|
||||||
Filtering;
|
|
||||||
Reducing;
|
|
||||||
`lambda` Expression)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/01_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/01_content.ipynb)
|
|
||||||
(`list` Comprehension;
|
|
||||||
`generator` Expression;
|
|
||||||
Streams of Data;
|
|
||||||
Boolean Reducers)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/02_exercises_outliers.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/02_exercises_outliers.ipynb)
|
|
||||||
(Removing Outliers in Streaming Data)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/03_exercises_un-packing.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/03_exercises_un-packing.ipynb)
|
|
||||||
(Packing & Unpacking with Functions, continued)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/04_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/08_mfr/04_content.ipynb)
|
|
||||||
(Iterators vs. Iterables;
|
|
||||||
Example: `sorted()` vs. `reversed()`)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/05_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/08_mfr/06_review.ipynb)
|
|
||||||
- *Chapter 9*: Mappings & Sets
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/00_content.ipynb)
|
|
||||||
(`dict` Type;
|
|
||||||
Nested Data;
|
|
||||||
Hash Tables;
|
|
||||||
`dict` Methods & Behavior;
|
|
||||||
`dict` Comprehension)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/01_exercises_nested-data.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/01_exercises_nested-data.ipynb)
|
|
||||||
(Working with Nested Data)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/02_content.ipynb)
|
|
||||||
(`**kwargs` in Function Definitions;
|
|
||||||
Memoization)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/03_exercises_fibonacci.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/03_exercises_fibonacci.ipynb)
|
|
||||||
(Memoization without Side Effects)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/04_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/04_content.ipynb)
|
|
||||||
(`set` Type;
|
|
||||||
`set` Methods & Operations;
|
|
||||||
`set` Comprehension;
|
|
||||||
`frozenset` Type)
|
|
||||||
- [appendix <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/05_appendix.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/05_appendix.ipynb)
|
|
||||||
(`defaultdict` Type;
|
|
||||||
`Counter` Type;
|
|
||||||
`ChainMap` Type)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/06_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/07_review.ipynb)
|
|
||||||
- [further resources <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/09_mappings/08_resources.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/09_mappings/08_resources.ipynb)
|
|
||||||
- *Chapter 10*: Arrays & Dataframes
|
|
||||||
- *Chapter 11*: Classes & Instances
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/00_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/00_content.ipynb)
|
|
||||||
(`class` Statement;
|
|
||||||
Instantiation;
|
|
||||||
Text Representations;
|
|
||||||
Instance Methods vs. Class Methods;
|
|
||||||
Computed Properties)
|
|
||||||
- [exercises <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/01_exercises_tsp.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/01_exercises_tsp.ipynb)
|
|
||||||
(A Traveling Salesman Problem)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/02_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/02_content.ipynb)
|
|
||||||
(Sequence Emulation & Iteration;
|
|
||||||
Python's Data Model;
|
|
||||||
(Im)mutable Data Types;
|
|
||||||
Method Chaining;
|
|
||||||
Polymorphism)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/03_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/03_content.ipynb)
|
|
||||||
(Operator Overloading: Arithmetic & Relational Operators;
|
|
||||||
Number Emulation)
|
|
||||||
- [content <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/04_content.ipynb)
|
|
||||||
[<img height="12" style="display: inline-block" src="static/link/to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/main?urlpath=lab/tree/11_classes/04_content.ipynb)
|
|
||||||
(Writing one's own Packages;
|
|
||||||
The final `Vector` & `Matrix` Classes;
|
|
||||||
Comparison with `numpy`)
|
|
||||||
- [summary <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/05_summary.ipynb)
|
|
||||||
- [review questions <img height="12" style="display: inline-block" src="static/link/to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/main/11_classes/06_review.ipynb)
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2024 Alexander Hess [alexander@webartifex.biz]
|
Copyright (c) 2019 Alexander Hess [alexander@webartifex.biz]
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
487
README.md
487
README.md
|
|
@ -1,257 +1,296 @@
|
||||||
# An Introduction to Python and Programming
|
# An Introduction to Python and Programming
|
||||||
|
|
||||||
This project is a *thorough* introductory course
|
The purpose of this repository is to serve as an interactive book for a
|
||||||
in programming with **[Python <img height="12" style="display: inline-block" src="static/link/to_py.png">](https://www.python.org/)**.
|
thorough introductory course on programming in the
|
||||||
|
**[Python <img height="12" style="display: inline-block" src="static/link_to_py.png">](https://www.python.org/)**
|
||||||
|
language.
|
||||||
|
|
||||||
|
The course's **main goal** is to **prepare** the student for **further
|
||||||
|
studies** in the "field" of **data science**.
|
||||||
|
|
||||||
### Table of Contents
|
The chapters are laid out in [Jupyter notebooks <img height="12" style="display: inline-block" src="static/link_to_jp.png">](https://jupyter-notebook.readthedocs.io/en/stable/)
|
||||||
|
which are a de-facto standard for exchanging code and analyses among data
|
||||||
The following is a high-level overview of the contents.
|
science professionals and researchers.
|
||||||
For a more *detailed version* with **clickable links**
|
They can be viewed in a web browser either statically on [nbviewer <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/tree/master/)
|
||||||
see the [CONTENTS.md](CONTENTS.md) file.
|
or interactively (i.e., you can execute the code) on [mybinder <img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab):
|
||||||
|
|
||||||
- *Chapter 0*: Introduction
|
- *Chapter 0*: Introduction
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/00_intro_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=YTU8jaG27Xk&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/00_intro_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/00_intro_02_exercises.ipynb))
|
||||||
- **Part A: Expressing Logic**
|
- **Part A: Expressing Logic**
|
||||||
- *Chapter 1*: Elements of a Program
|
- *Chapter 1*: Elements of a Program
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/01_elements_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=v0lk1Qfaw8Y&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/01_elements_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/01_elements_02_exercises.ipynb))
|
||||||
- *Chapter 2*: Functions & Modularization
|
- *Chapter 2*: Functions & Modularization
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/02_functions_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=j4Xn8QFysmc&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/02_functions_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/02_functions_02_exercises.ipynb))
|
||||||
- *Chapter 3*: Conditionals & Exceptions
|
- *Chapter 3*: Conditionals & Exceptions
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/03_conditionals_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=aDbblINzuGQ&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/03_conditionals_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/03_conditionals_02_exercises.ipynb))
|
||||||
- *Chapter 4*: Recursion & Looping
|
- *Chapter 4*: Recursion & Looping
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=jT6hr4vOJks&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_01_review.ipynb)
|
||||||
|
| [exercises 1 <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_02_exercises.ipynb)
|
||||||
|
| [exercises 2 <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_03_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/04_iteration_03_exercises.ipynb))
|
||||||
- **Part B: Managing Data and Memory**
|
- **Part B: Managing Data and Memory**
|
||||||
- *Chapter 5*: Numbers & Bits
|
- *Chapter 5*: Numbers & Bits
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/05_numbers_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=nB00WGCnVjg&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/05_numbers_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/05_numbers_02_exercises.ipynb))
|
||||||
- *Chapter 6*: Text & Bytes
|
- *Chapter 6*: Text & Bytes
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/06_text_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=3WTRlgN09sM&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/06_text_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/06_text_02_exercises.ipynb))
|
||||||
- *Chapter 7*: Sequential Data
|
- *Chapter 7*: Sequential Data
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/07_sequences_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=nx2sCDoeC3I&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/07_sequences_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/07_sequences_02_exercises.ipynb))
|
||||||
- *Chapter 8*: Map, Filter, & Reduce
|
- *Chapter 8*: Map, Filter, & Reduce
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/08_mfr_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=ePzzq2YBWjY&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/08_mfr_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mfr_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/08_mfr_02_exercises.ipynb))
|
||||||
- *Chapter 9*: Mappings & Sets
|
- *Chapter 9*: Mappings & Sets
|
||||||
- *Chapter 10*: Arrays & Dataframes
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_00_content.ipynb)
|
||||||
- *Chapter 11*: Classes & Instances
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/09_mappings_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=vbp0svA35TE&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/09_mappings_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_mappings_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/09_mappings_02_exercises.ipynb))
|
||||||
|
- *Chapter 10*: Classes & Instances
|
||||||
|
([content <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/10_classes_00_content.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/watch?v=ibDT0uOAOTI&list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f)
|
||||||
|
| [review <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_01_review.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/10_classes_01_review.ipynb)
|
||||||
|
| [exercises <img height="12" style="display: inline-block" src="static/link_to_nb.png">](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/10_classes_02_exercises.ipynb)
|
||||||
|
[<img height="12" style="display: inline-block" src="static/link_to_mb.png">](https://mybinder.org/v2/gh/webartifex/intro-to-python/master?urlpath=lab/tree/10_classes_02_exercises.ipynb))
|
||||||
|
|
||||||
|
However, it is recommended to **install Python and [Jupyter <img height="12" style="display: inline-block" src="static/link_to_jp.png">](https://jupyter.org)
|
||||||
|
locally** and run the code in the notebooks on one's own machine in the [JupyterLab <img height="12" style="display: inline-block" src="static/link_to_jp.png">](https://jupyterlab.readthedocs.io/en/stable/)
|
||||||
|
application.
|
||||||
|
Precise **installation instructions** are either in [Chapter 0 <img height="12" style="display: inline-block" src="static/link_to_nb.png">](
|
||||||
|
https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_content.ipynb#Installation)
|
||||||
|
or further below.
|
||||||
|
|
||||||
|
|
||||||
#### Videos
|
### Feedback
|
||||||
|
|
||||||
Presentations of the chapters are available on this [YouTube playlist <img height="12" style="display: inline-block" src="static/link/to_yt.png">](https://www.youtube.com/playlist?list=PL-2JV1G3J10kRUPgP7EwLhyeN5lOZW2kH).
|
|
||||||
The recordings are about 25 hours long in total
|
|
||||||
and were made in spring 2020
|
|
||||||
after a corresponding in-class Bachelor course was cancelled due to Corona.
|
|
||||||
|
|
||||||
|
|
||||||
### Objective
|
|
||||||
|
|
||||||
The **main goal** is to **prepare** students
|
|
||||||
for **further studies** in the "field" of **data science**,
|
|
||||||
including but not limited to topics such as:
|
|
||||||
- algorithms & data structures
|
|
||||||
- data cleaning & wrangling
|
|
||||||
- data visualization
|
|
||||||
- data engineering (incl. SQL databases)
|
|
||||||
- data mining (incl. web scraping)
|
|
||||||
- linear algebra
|
|
||||||
- machine learning (incl. feature generation & deep learning)
|
|
||||||
- optimization & (meta-)heuristics (incl. management science & operations research)
|
|
||||||
- statistics & econometrics
|
|
||||||
- quantitative finance (e.g., option valuation)
|
|
||||||
- quantitative marketing (e.g., customer segmentation)
|
|
||||||
- quantitative supply chain management (e.g., forecasting)
|
|
||||||
- web development (incl. APIs)
|
|
||||||
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
To be suitable for *beginners*, there are *no* formal prerequisites.
|
|
||||||
It is only expected that the student has:
|
|
||||||
- a *solid* understanding of the **English** language,
|
|
||||||
- knowledge of **basic mathematics** from high school,
|
|
||||||
- the ability to **think conceptually** and **reason logically**, and
|
|
||||||
- the willingness to **invest** around **90-120 hours** on this course.
|
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
If you are a total beginner,
|
|
||||||
follow the instructions in the "Installation" section next.
|
|
||||||
If you are familiar with
|
|
||||||
the [git](https://git-scm.com/)
|
|
||||||
and [poetry](https://python-poetry.org/docs/) command-line tools,
|
|
||||||
you may want to look at the "Alternative Installation" section further below.
|
|
||||||
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
To follow this course, an installation of **Python 3.11** or higher is expected.
|
|
||||||
|
|
||||||
A popular and beginner friendly way is
|
|
||||||
to install the [Anaconda Distribution](https://www.anaconda.com/download)
|
|
||||||
that not only ships Python itself
|
|
||||||
but also comes pre-packaged with a lot of third-party libraries.
|
|
||||||
|
|
||||||
<img src="static/anaconda_download.png" width="50%">
|
|
||||||
|
|
||||||
Scroll down to the "Anaconda Installers" section
|
|
||||||
and install the latest version for your operating system
|
|
||||||
(i.e., *2024-02* with Python 3.11 at the time of this writing).
|
|
||||||
|
|
||||||
After installation,
|
|
||||||
you find an entry "[Anaconda Navigator](https://docs.anaconda.com/free/navigator/)"
|
|
||||||
in your start menu.
|
|
||||||
Click on it.
|
|
||||||
|
|
||||||
<img src="static/anaconda_start_menu.png" width="50%">
|
|
||||||
|
|
||||||
A window opens giving you several options to start various applications.
|
|
||||||
In the beginning, we will work mostly with [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/).
|
|
||||||
Click on "Launch".
|
|
||||||
|
|
||||||
<img src="static/anaconda_navigator.png" width="50%">
|
|
||||||
|
|
||||||
A new tab in your web browser opens:
|
|
||||||
The website is "localhost" and some number (e.g., 8888).
|
|
||||||
|
|
||||||
This is the [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) application
|
|
||||||
that is used to display the course materials.
|
|
||||||
On the left, you see the files and folders on your computer.
|
|
||||||
This file browser works like any other.
|
|
||||||
In the center, you see several options to launch (i.e., "create") new files.
|
|
||||||
|
|
||||||
<img src="static/jupyter_lab.png" width="50%">
|
|
||||||
|
|
||||||
To check if your Python installation works,
|
|
||||||
double-click on the "Python 3" tile under the "Notebook" section.
|
|
||||||
That opens a new [Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/stable/)
|
|
||||||
named "Untitled.ipynb".
|
|
||||||
|
|
||||||
<img src="static/jupyter_notebook_blank.png" width="50%">
|
|
||||||
|
|
||||||
Enter some basic Python in the **code cell**, for example, `1 + 2`.
|
|
||||||
Then, press the **Enter** key *while* holding down the **Control** key
|
|
||||||
(if that does not work, try with the **Shift** key)
|
|
||||||
to **execute** the snippet.
|
|
||||||
The result of the calculation, `3` in the example, shows up below the cell.
|
|
||||||
|
|
||||||
<img src="static/jupyter_notebook_example.png" width="50%">
|
|
||||||
|
|
||||||
After setting up Python,
|
|
||||||
click on the green "Code" button on the top right on this website
|
|
||||||
to download the course materials.
|
|
||||||
As a beginner, choosing "Download ZIP" is likely the easiest option.
|
|
||||||
Then, unpack the ZIP file into a folder of your choice,
|
|
||||||
ideally somewhere within your personal user folder
|
|
||||||
so that the files show up right away in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/).
|
|
||||||
|
|
||||||
<img src="static/repo_download.png" width="50%">
|
|
||||||
|
|
||||||
|
|
||||||
### Alternative Installation (for Instructors using Linux)
|
|
||||||
|
|
||||||
Python can also be installed in a "pure" way
|
|
||||||
obtained directly from its core development team [here](https://www.python.org/downloads/).
|
|
||||||
Then, it comes *without* any third-party packages,
|
|
||||||
which is *not* a problem at all.
|
|
||||||
Managing third-party packages can be automated to a large degree,
|
|
||||||
for example, with tools such as [poetry](https://python-poetry.org/docs/).
|
|
||||||
|
|
||||||
However, this may be too "advanced" for a beginner
|
|
||||||
as it involves working with a [command-line interface <img height="12" style="display: inline-block" src="static/link/to_wiki.png">](https://en.wikipedia.org/wiki/Command-line_interface) (CLI),
|
|
||||||
also called a **terminal**,
|
|
||||||
which looks like the one below.
|
|
||||||
It is used *without* a mouse by typing commands into it.
|
|
||||||
The following instructions assume that
|
|
||||||
[git](https://git-scm.com/), [poetry](https://python-poetry.org/docs/),
|
|
||||||
and [pyenv](https://github.com/pyenv/pyenv) are installed.
|
|
||||||
|
|
||||||
<img src="static/cli_install.png" width="50%" align="center">
|
|
||||||
|
|
||||||
The screenshot above shows how this project can be set up in an alternative way
|
|
||||||
with the [zsh](https://en.wikipedia.org/wiki/Z_shell) CLI.
|
|
||||||
|
|
||||||
First, [git](https://git-scm.com/) is used
|
|
||||||
to **clone** the course materials as a **repository**
|
|
||||||
into a new folder called "*intro-to-python*"
|
|
||||||
that lives under a "*repos*" folder.
|
|
||||||
|
|
||||||
- `git clone https://github.com/webartifex/intro-to-python.git`
|
|
||||||
|
|
||||||
The `cd` command is used to "change directories".
|
|
||||||
|
|
||||||
In the screenshot, [pyenv](https://github.com/pyenv/pyenv) is used
|
|
||||||
to set the project's Python version.
|
|
||||||
[pyenv](https://github.com/pyenv/pyenv)'s purpose is
|
|
||||||
to manage *many* parallel Python installations on the same computer.
|
|
||||||
It is highly recommended for professional users;
|
|
||||||
however, any other way of installing Python works as well.
|
|
||||||
|
|
||||||
- `pyenv local ...`
|
|
||||||
|
|
||||||
On the contrary, [poetry](https://python-poetry.org/docs/)'s purpose is
|
|
||||||
to manage third-party packages within the *same* Python installation
|
|
||||||
and, more importantly, on a per-project basis.
|
|
||||||
So, for example,
|
|
||||||
whereas "Project A" may depend on [numpy](https://numpy.org/) *v1.19*
|
|
||||||
from June 2020 be installed,
|
|
||||||
"Project B" may use *v1.14* from January 2018 instead
|
|
||||||
(cf., numpy's [release history](https://pypi.org/project/numpy/#history)).
|
|
||||||
To achieve this per-project **isolation**,
|
|
||||||
[poetry](https://python-poetry.org/docs/) uses so-called **virtual environments**
|
|
||||||
behind the scenes.
|
|
||||||
While one could do that manually,
|
|
||||||
for example, by using Python's built-in
|
|
||||||
[venv <img height="12" style="display: inline-block" src="static/link/to_py.png">](https://docs.python.org/3/library/venv.html) module,
|
|
||||||
it is more convenient and reliable to have [poetry](https://python-poetry.org/docs/)
|
|
||||||
automate this.
|
|
||||||
The following *one* command not only
|
|
||||||
creates a new virtual environment (manually: `python -m venv venv`)
|
|
||||||
and *activates* it (manually: `source venv/bin/activate`),
|
|
||||||
it also installs the versions of the project's third-party dependencies
|
|
||||||
as specified in the [poetry.lock](poetry.lock) file
|
|
||||||
(manually: `python -m pip install -r requirements.txt`
|
|
||||||
if a [requirements.txt](https://docs.python.org/3/tutorial/venv.html#managing-packages-with-pip)
|
|
||||||
file is used;
|
|
||||||
the `python -m` part is often left out [but should not be](https://snarky.ca/why-you-should-use-python-m-pip/)):
|
|
||||||
|
|
||||||
- `poetry install`
|
|
||||||
|
|
||||||
[poetry](https://python-poetry.org/docs/) is also used
|
|
||||||
to execute commands in the project's (virtual) environment.
|
|
||||||
To do that, the command is prefixed with `poetry run ...`.
|
|
||||||
|
|
||||||
The project uses [nox](https://nox.thea.codes/en/stable/)
|
|
||||||
to manage various maintenance tasks.
|
|
||||||
After cloning the repository and setting up the virual environment,
|
|
||||||
it is recommended to run the initialization task.
|
|
||||||
That needs to be done only once.
|
|
||||||
|
|
||||||
- `poetry run nox -s init-project`
|
|
||||||
|
|
||||||
To do the equivalent of clicking "Launch" in the Anaconda Navigator:
|
|
||||||
|
|
||||||
- `poetry run jupyter lab`
|
|
||||||
|
|
||||||
This opens a new tab in your web browser just as above.
|
|
||||||
The command-line interface stays open in the background,
|
|
||||||
like in the screenshot below,
|
|
||||||
and prints log messages as we work in [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/).
|
|
||||||
|
|
||||||
<img src="static/cli_jupyter_lab.png" width="50%" align="center">
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Feedback **is highly encouraged** and will be incorporated.
|
Feedback **is highly encouraged** and will be incorporated.
|
||||||
Open an issue in the [issues tracker <img height="12" style="display: inline-block" src="static/link/to_gh.png">](https://github.com/webartifex/intro-to-python/issues)
|
Simply open an issue in the [issues tracker <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://github.com/webartifex/intro-to-python/issues)
|
||||||
or initiate a [pull request <img height="12" style="display: inline-block" src="static/link/to_gh.png">](https://help.github.com/en/articles/about-pull-requests)
|
or initiate a [pull request <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://help.github.com/en/articles/about-pull-requests)
|
||||||
if you are familiar with the concept.
|
if you are familiar with the concept.
|
||||||
Simple issues that *anyone* can **help fix** are, for example,
|
Simple issues that anyone can **help fix** are, for example,
|
||||||
**spelling mistakes** or **broken links**.
|
**spelling mistakes** or **broken links**.
|
||||||
If you feel that some topic is missing entirely, you may also mention that.
|
If you feel that some topic is missing entirely, you may also mention that.
|
||||||
The materials here are considered a **permanent work-in-progress**.
|
The materials here are considered a **permanent work-in-progress**.
|
||||||
|
|
||||||
A "Show HN" post about this course was made on [Hacker News <img height="12" style="display: inline-block" src="static/link/to_hn.png">](https://news.ycombinator.com/item?id=22669084)
|
A "Show HN" post about this course was made on [Hacker News <img height="12" style="display: inline-block" src="static/link_to_hn.png">](https://news.ycombinator.com/item?id=22669084)
|
||||||
and some ideas for improvement were discussed there.
|
and some ideas for improvement were discussed there.
|
||||||
|
|
||||||
|
|
||||||
|
### Videos
|
||||||
|
|
||||||
|
Presentations on the chapters are available either via the individual links to
|
||||||
|
[YouTube <img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com)
|
||||||
|
above or this [playlist <img height="12" style="display: inline-block" src="static/link_to_yt.png">](https://www.youtube.com/playlist?list=PL-2JV1G3J10lQ2xokyQowcRJI5jjNfW7f).
|
||||||
|
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
To be suitable for *total beginners*, there are *no* formal prerequisites.
|
||||||
|
It is only expected that the student has:
|
||||||
|
|
||||||
|
- a *solid* understanding of the **English language**,
|
||||||
|
- knowledge of **basic mathematics** from high school,
|
||||||
|
- the ability to **think conceptually** and **reason logically**, and
|
||||||
|
- the willingness to **invest around 90 - 120 hours on this course**.
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To follow this course, a working installation of **Python 3.7** or higher is
|
||||||
|
expected.
|
||||||
|
|
||||||
|
A popular and beginner friendly way is to install the [Anaconda Distribution](
|
||||||
|
https://www.anaconda.com/distribution/) that not only ships Python but comes
|
||||||
|
pre-packaged with a lot of third-party libraries from the so-called
|
||||||
|
"scientific stack".
|
||||||
|
Just go to the [download](https://www.anaconda.com/distribution/#download-section)
|
||||||
|
section and install the latest version (i.e., *2019-10* with Python 3.7 at the
|
||||||
|
time of this writing) for your operating system.
|
||||||
|
|
||||||
|
Then, among others, you will find an entry "[Anaconda Navigator](https://docs.anaconda.com/anaconda/navigator/)"
|
||||||
|
in your start menu like below.
|
||||||
|
Click on it.
|
||||||
|
|
||||||
|
<img src="static/anaconda_start_menu.png" width="30%">
|
||||||
|
|
||||||
|
A window opens showing you several applications that come with the Anaconda
|
||||||
|
Distribution.
|
||||||
|
Now, click on "JupyterLab."
|
||||||
|
|
||||||
|
<img src="static/anaconda_navigator.png" width="50%">
|
||||||
|
|
||||||
|
A new tab in your web browser opens with the website being "localhost" and some
|
||||||
|
number (e.g., 8888).
|
||||||
|
This is the [JupyterLab <img height="12" style="display: inline-block" src="static/link_to_jp.png">](https://jupyterlab.readthedocs.io/en/stable/)
|
||||||
|
application that is used to display and run the notebooks mentioned above.
|
||||||
|
On the left, you see the files and folders in your local user folder.
|
||||||
|
This file browser works like any other.
|
||||||
|
In the center, you have several options to launch (i.e., "create") new files.
|
||||||
|
|
||||||
|
<img src="static/jupyter_lab.png" width="50%">
|
||||||
|
|
||||||
|
Next, to download the course's materials as a ZIP file, click on the green
|
||||||
|
"Clone or download" button on the top right on this website.
|
||||||
|
Then, unpack the ZIP file into a folder of your choosing, ideally somewhere
|
||||||
|
within your personal user folder so that the files show up right away in
|
||||||
|
JupyterLab.
|
||||||
|
|
||||||
|
|
||||||
|
### Alternative Installation (for Instructors)
|
||||||
|
|
||||||
|
Python can also be installed in a "pure" way as obtained from its core
|
||||||
|
development team (i.e., without any third-party packages installed).
|
||||||
|
However, this may be too "advanced" for a beginner as it involves working
|
||||||
|
with a [terminal emulator <img height="12" style="display: inline-block" src="static/link_to_wiki.png">](https://en.wikipedia.org/wiki/Terminal_emulator),
|
||||||
|
which looks like the one in the picture below and is used *without* a mouse by
|
||||||
|
typing commands into it.
|
||||||
|
|
||||||
|
<img src="static/terminal.png" width="50%" align="center">
|
||||||
|
|
||||||
|
Assuming that you already have a working version of Python 3.7 or higher
|
||||||
|
installed (cf., the official [download page <img height="12" style="display: inline-block" src="static/link_to_py.png">](https://www.python.org/downloads/)),
|
||||||
|
the following summarizes the commands to be typed into a terminal emulator to
|
||||||
|
get the course materials up and running on a local machine without the
|
||||||
|
Anaconda Distribution.
|
||||||
|
You are then responsible for understanding the concepts behind them.
|
||||||
|
|
||||||
|
First, the [git](https://git-scm.com/) command line tool is a more professional
|
||||||
|
way of "cloning" the course materials as compared to downloading them in a ZIP
|
||||||
|
file.
|
||||||
|
|
||||||
|
- `git clone https://github.com/webartifex/intro-to-python.git`
|
||||||
|
|
||||||
|
This creates a new folder *intro-to-python* with all the materials of this
|
||||||
|
repository in it.
|
||||||
|
|
||||||
|
Inside this folder, it is recommended to create a so-called **virtual
|
||||||
|
environment** with Python's [venv <img height="12" style="display: inline-block" src="static/link_to_py.png">](https://docs.python.org/3/library/venv.html)
|
||||||
|
module.
|
||||||
|
This must only be done the first time.
|
||||||
|
A virtual environment is a way of *isolating* the third-party packages
|
||||||
|
installed by different projects, which is considered a best practice.
|
||||||
|
|
||||||
|
- `python -m venv venv`
|
||||||
|
|
||||||
|
The second *venv* is the environment's name and by convention often chosen to
|
||||||
|
be *venv*.
|
||||||
|
However, it could be another name as well.
|
||||||
|
|
||||||
|
From then on, each time you want to resume work, go back into the
|
||||||
|
*intro-to-python* folder inside your terminal and "activate" the virtual
|
||||||
|
environment (*venv* is the name chosen before).
|
||||||
|
|
||||||
|
- `source venv/bin/activate`
|
||||||
|
|
||||||
|
This may change how the terminal's [command prompt <img height="12" style="display: inline-block" src="static/link_to_wiki.png">](https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt)
|
||||||
|
looks.
|
||||||
|
|
||||||
|
[poetry](https://poetry.eustace.io/docs/) and [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)
|
||||||
|
are popular tools to automate the described management of virtual environments.
|
||||||
|
|
||||||
|
After activation for the first time, you must install the project's
|
||||||
|
**dependencies** (= the third-party packages needed to run the code), most
|
||||||
|
notably [JupyterLab <img height="12" style="display: inline-block" src="static/link_to_jp.png">](https://pypi.org/project/jupyterlab/) in this project
|
||||||
|
(the "python -m" is often left out [but should not be](https://snarky.ca/why-you-should-use-python-m-pip/);
|
||||||
|
if you have poetry installed, you may just type `poetry install` instead).
|
||||||
|
|
||||||
|
- `python -m pip install -r requirements.txt`
|
||||||
|
|
||||||
|
With everything installed, you can now do the equivalent of clicking the
|
||||||
|
"JupyterLab" entry in the Anaconda Navigator.
|
||||||
|
|
||||||
|
- `jupyter lab`
|
||||||
|
|
||||||
|
This opens a new tab in your web browser just as above.
|
||||||
|
|
||||||
|
|
||||||
|
#### Interactive Presentation Mode & Live Coding
|
||||||
|
|
||||||
|
The *requirements.txt* file also installs the [nbextensions <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://github.com/ipython-contrib/jupyter_contrib_nbextensions)
|
||||||
|
for Jupyter notebooks, the [black <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://github.com/psf/black)
|
||||||
|
code formatting tool (incl. the [blackcellmagic <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://github.com/csurfer/blackcellmagic)
|
||||||
|
Jupyter extension) and the [RISE <img height="12" style="display: inline-block" src="static/link_to_gh.png">](https://github.com/damianavila/RISE)
|
||||||
|
Jupyter extension.
|
||||||
|
With them, the instructor can easily re-format code in a class session and
|
||||||
|
execute code in presentation mode.
|
||||||
|
|
||||||
|
**Note**: Currently, the RISE extension *only* works with the older
|
||||||
|
notebook command.
|
||||||
|
|
||||||
|
- `jupyter notebook` (so, `jupyter lab` may *not* be used).
|
||||||
|
|
||||||
|
After installing the dependencies, the instructor must copy the extensions'
|
||||||
|
JavaScript and CSS files into Jupyter's search directory.
|
||||||
|
|
||||||
|
- `jupyter contrib nbextension install --user`
|
||||||
|
|
||||||
|
Now, the instructor can enable/disable the various Jupyter notebook
|
||||||
|
extensions.
|
||||||
|
|
||||||
|
**Note**: The extension "Collapsible Headings" may interfere with the
|
||||||
|
RISE presentation if hotkeys are enabled.
|
||||||
|
|
||||||
|
|
||||||
## About the Author
|
## About the Author
|
||||||
|
|
||||||
Alexander Hess is a PhD student
|
Alexander Hess is a PhD student at the Chair of Logistics Management at the
|
||||||
at the Chair of Logistics Management at [WHU - Otto Beisheim School of Management](https://www.whu.edu)
|
[WHU - Otto Beisheim School of Management](https://www.whu.edu) where he
|
||||||
where he conducts research on urban delivery platforms
|
conducts research on urban delivery platforms and teaches an introductory
|
||||||
and teaches coding courses based on Python in the BSc and MBA programs.
|
course on Python (cf., [Fall Term 2019](https://vlv.whu.edu/campus/all/event.asp?objgguid=0xE57C2715B01B441AAFD3E79AA05CACCF&from=vvz&gguid=0x6A2B0ED5B2B949E69957A2099E7DE2F1&mode=own&tguid=0x3980A9BBC3BF4A638E977F2DC163F44B&lang=en),
|
||||||
|
[Spring Term 2020](https://vlv.whu.edu/campus/all/event.asp?objgguid=0x3354F4C108FF4E959CDD692A325D9AFE&from=vvz&gguid=0x262E29795DD742CFBDE72B12B69CEFD6&mode=own&lang=en&tguid=0x2E4A7D1FF3C34AD08FF07685461781C9)).
|
||||||
|
|
||||||
Connect him on [LinkedIn](https://www.linkedin.com/in/webartifex).
|
Connect him on [LinkedIn](https://www.linkedin.com/in/webartifex).
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue