diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..2b5e489b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. ... + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Where did you run the tutorial?** + - Binder + - Docker + - Local installation + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..59094e26 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4949cf23..b1ade494 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,21 +18,21 @@ repos: - id: isort args: [--profile, black, --filter-files] - repo: https://github.com/PyCQA/autoflake - rev: v2.2.1 + rev: v2.3.1 hooks: - id: autoflake - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 + rev: v3.15.2 hooks: - id: pyupgrade args: [--py38-plus] - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.3.0 hooks: - id: black language_version: python3 # Should be a command that runs python3.6+ - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 args: [--count, --show-source, --statistics] @@ -63,6 +63,6 @@ repos: hooks: - id: setup-cfg-fmt - repo: https://github.com/kynan/nbstripout - rev: 0.6.1 + rev: 0.7.1 hooks: - id: nbstripout diff --git a/control_flow.ipynb b/control_flow.ipynb index 1e761d2c..9edd6fdc 100644 --- a/control_flow.ipynb +++ b/control_flow.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "9e22fc36-19ab-4aa9-8b5c-d631a287e924", + "id": "0", "metadata": {}, "source": [ "# Control flow" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "5a1222fe", + "id": "1", "metadata": {}, "source": [ "# Table of contents\n", @@ -42,7 +42,7 @@ }, { "cell_type": "markdown", - "id": "5e5bb08a-2045-411b-8792-8cb255e9f066", + "id": "2", "metadata": {}, "source": [ "## References" @@ -50,7 +50,7 @@ }, { "cell_type": "markdown", - "id": "d79e417f-e04a-4f44-a2da-0759a5f845cf", + "id": "3", "metadata": {}, "source": [ "From \"Python 4 Everybody\" online tutorial:\n", @@ -61,7 +61,7 @@ }, { "cell_type": "markdown", - "id": "74f5fff2-1321-49c3-aaa5-0151bb87fced", + "id": "4", "metadata": { "tags": [] }, @@ -71,7 +71,7 @@ }, { "cell_type": "markdown", - "id": "c77d7858-0f56-4925-9724-689aadbb23a7", + "id": "5", "metadata": {}, "source": [ "Python [supports](./basic_datatypes.ipynb#Comparison-operators) different comparison expressions. They return either `True` or `False`.\n", @@ -81,7 +81,7 @@ }, { "cell_type": "markdown", - "id": "0d1335e1-76e8-48ad-907a-a9b9d14c61a5", + "id": "6", "metadata": {}, "source": [ "The main conditional is the `if-elif-else` block:\n", @@ -107,7 +107,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f79d4a60", + "id": "7", "metadata": { "tags": [] }, @@ -140,7 +140,7 @@ }, { "cell_type": "markdown", - "id": "086bd853-ed18-4d16-8a34-44675faa860c", + "id": "8", "metadata": { "tags": [] }, @@ -150,7 +150,7 @@ }, { "cell_type": "markdown", - "id": "2f047b04-c9c0-49b3-8476-f7aa31a45bb6", + "id": "9", "metadata": {}, "source": [ "`while` loops repeat a block of code until some condition remains true.\n", @@ -170,7 +170,7 @@ }, { "cell_type": "markdown", - "id": "6d6d18f4-a797-4a3a-acd7-76a5e3d29f8c", + "id": "10", "metadata": {}, "source": [ "A very simple example:" @@ -179,7 +179,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2d7f000c-6b7a-44e8-bc96-0fe677ceeea3", + "id": "11", "metadata": { "tags": [] }, @@ -195,7 +195,7 @@ }, { "cell_type": "markdown", - "id": "7d975ebe", + "id": "12", "metadata": {}, "source": [ "First, `n` is initialized to 1.\n", @@ -208,7 +208,7 @@ }, { "cell_type": "markdown", - "id": "8e5c5a4d-3a5d-43ad-a5dc-abb53799b71d", + "id": "13", "metadata": {}, "source": [ "\n", @@ -237,7 +237,7 @@ }, { "cell_type": "markdown", - "id": "96aaf8c7-3c4b-4547-8f62-cf49f840159b", + "id": "14", "metadata": { "tags": [] }, @@ -247,7 +247,7 @@ }, { "cell_type": "markdown", - "id": "2b2eac3c-c83d-482b-975b-7b7787206310", + "id": "15", "metadata": {}, "source": [ "In Python, an **iterable** is an **object** capable of returning its members one at a time.\n", @@ -263,7 +263,7 @@ }, { "cell_type": "markdown", - "id": "fd11a026-1d83-437c-8a41-263ed76ed764", + "id": "16", "metadata": {}, "source": [ "In other languages (C++, Java or JavaScript), a `for` loop is more similar to `while` in Python. For example, the C++ loop\n", @@ -306,7 +306,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9ca56906-4c43-4d0c-acf6-07a1370299d9", + "id": "17", "metadata": { "tags": [] }, @@ -318,7 +318,7 @@ }, { "cell_type": "markdown", - "id": "bcf00919-de04-4406-8c9a-5ee9b80a0623", + "id": "18", "metadata": {}, "source": [ "The loops runs until there are letters in the string `'Python'`, as strings are iterable.\n", @@ -328,7 +328,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4c97b210-1fa9-4d73-b156-5306e0b9c256", + "id": "19", "metadata": { "tags": [] }, @@ -344,7 +344,7 @@ }, { "cell_type": "markdown", - "id": "e3f2fdf7-d032-4c69-975c-704acae75ade", + "id": "20", "metadata": {}, "source": [ "Why writing six lines of code when we can do the same with just two?" @@ -352,7 +352,7 @@ }, { "cell_type": "markdown", - "id": "5b0747a4", + "id": "21", "metadata": {}, "source": [ "### The `enumerate` built-in\n", @@ -365,7 +365,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1782af19", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -375,7 +375,7 @@ }, { "cell_type": "markdown", - "id": "75cb8fcd-6cb7-4c04-a843-3369eb41e066", + "id": "23", "metadata": {}, "source": [ "### The `range` built-in\n", @@ -395,7 +395,7 @@ }, { "cell_type": "markdown", - "id": "efb1a53e-a447-4808-bbb3-34a614d35735", + "id": "24", "metadata": { "tags": [] }, @@ -416,7 +416,7 @@ { "cell_type": "code", "execution_count": null, - "id": "530cb91a-1243-401b-84a0-ff7973833908", + "id": "25", "metadata": { "tags": [] }, @@ -427,7 +427,7 @@ }, { "cell_type": "markdown", - "id": "e23dfd66-a14b-4346-af3d-9b1419063c84", + "id": "26", "metadata": {}, "source": [ "#### 1. Write a Python program that returns the characters in a string and their indexes\n", @@ -444,7 +444,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4eb8fcdc-eed6-469b-891b-817e8b4dd23c", + "id": "27", "metadata": { "tags": [] }, @@ -461,7 +461,7 @@ }, { "cell_type": "markdown", - "id": "679b0816-3b20-4001-a39a-5558179bb9de", + "id": "28", "metadata": { "tags": [] }, @@ -477,7 +477,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c24d6340-4731-4776-b800-f2ef01f8afaf", + "id": "29", "metadata": { "tags": [] }, @@ -494,7 +494,7 @@ }, { "cell_type": "markdown", - "id": "9823551f-1ea7-44b7-9dc3-2e002331e334", + "id": "30", "metadata": { "tags": [] }, @@ -513,7 +513,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4fc3cab5-6d16-43a4-adf8-8560a0c29558", + "id": "31", "metadata": { "tags": [] }, @@ -532,7 +532,7 @@ }, { "cell_type": "markdown", - "id": "692f608f-2e79-4ad4-9a3d-ec9625941f81", + "id": "32", "metadata": {}, "source": [ "#### 4. Write a Python program that takes an integer and divides it by 2 until the result is no longer an even number" @@ -540,7 +540,7 @@ }, { "cell_type": "markdown", - "id": "2d06d01d-21a6-479d-bdbf-38de3151f9d3", + "id": "33", "metadata": {}, "source": [ "
\n", @@ -552,7 +552,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4d83467c-e736-4b27-b9c2-9ade4a70a918", + "id": "34", "metadata": { "tags": [] }, @@ -569,7 +569,7 @@ }, { "cell_type": "markdown", - "id": "e906c5d5-bc12-4829-b290-ed17ac1ddb3d", + "id": "35", "metadata": {}, "source": [ "---" @@ -577,7 +577,7 @@ }, { "cell_type": "markdown", - "id": "642d0ffe-b8c9-4076-a2e2-1b86722cf1a1", + "id": "36", "metadata": { "tags": [] }, @@ -587,7 +587,7 @@ }, { "cell_type": "markdown", - "id": "840b0480-9cc7-4947-8cf9-c375d9d267f5", + "id": "37", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -612,7 +612,7 @@ }, { "cell_type": "markdown", - "id": "c460c1d8-54c9-48cc-bf35-3395c78214fc", + "id": "38", "metadata": { "tags": [] }, @@ -622,7 +622,7 @@ }, { "cell_type": "markdown", - "id": "03709197-8bbc-4ba8-9f96-5e380ccc4484", + "id": "39", "metadata": {}, "source": [ "There are **4 ways** in which you can alter the normal execution of a loop:\n", @@ -637,7 +637,7 @@ }, { "cell_type": "markdown", - "id": "3fe08146-d503-4595-b031-ca765e8b3e77", + "id": "40", "metadata": {}, "source": [ "### `if` statement inside `for`/`while`\n", @@ -648,7 +648,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33c2bc7a-130a-40ef-8f9a-07eab5aa9283", + "id": "41", "metadata": { "tags": [] }, @@ -667,7 +667,7 @@ }, { "cell_type": "markdown", - "id": "9211f675-0cda-449e-bcd4-0fa3d4c2f3a8", + "id": "42", "metadata": {}, "source": [ "### The `break` keyword\n", @@ -678,7 +678,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b3ff6863-2dff-4dfb-a6f0-8d91f1801476", + "id": "43", "metadata": { "tags": [] }, @@ -696,7 +696,7 @@ }, { "cell_type": "markdown", - "id": "0e9e96a9-b55e-4862-9843-5dc8364f3673", + "id": "44", "metadata": {}, "source": [ "### The `continue` keyword\n", @@ -707,7 +707,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3cba31f4-4242-476d-a646-507e3e85fc1a", + "id": "45", "metadata": { "tags": [] }, @@ -723,7 +723,7 @@ }, { "cell_type": "markdown", - "id": "7076fd6d-524e-45b4-873e-ec86d5847e27", + "id": "46", "metadata": {}, "source": [ "### `else` after a `for`/`while`\n", @@ -736,7 +736,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d62ea1e6-9e05-41c1-85aa-5c5970fc6b85", + "id": "47", "metadata": { "tags": [] }, @@ -754,7 +754,7 @@ }, { "cell_type": "markdown", - "id": "c9ea4715", + "id": "48", "metadata": {}, "source": [ "Let's see what happens if we change the list to `[1, 2, 3, 4]`:" @@ -763,7 +763,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71be2a81", + "id": "49", "metadata": { "tags": [] }, @@ -781,7 +781,7 @@ }, { "cell_type": "markdown", - "id": "478550ff-87ad-45f5-adcb-1f486bfb5689", + "id": "50", "metadata": { "tags": [] }, @@ -791,7 +791,7 @@ }, { "cell_type": "markdown", - "id": "d192308f-eb06-4b39-b791-8df6514ca491", + "id": "51", "metadata": {}, "source": [ "Another way of controlling the flow of a program is by **catching exceptions**.\n", @@ -812,7 +812,7 @@ }, { "cell_type": "markdown", - "id": "542fdbf1-d9e5-4f71-baac-e66899c99292", + "id": "52", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -823,7 +823,7 @@ }, { "cell_type": "markdown", - "id": "5b1e549e-a24d-43b7-9531-e14383f64069", + "id": "53", "metadata": {}, "source": [ "When you can predict if a certain exception might occur, it's **always a good programming practice** to write what the program should do in that case\n", @@ -834,7 +834,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b7dc7edb-9398-4b8f-a0a9-d00a5c50e3f7", + "id": "54", "metadata": { "tags": [] }, @@ -852,7 +852,7 @@ }, { "cell_type": "markdown", - "id": "3c1e6903-4306-4255-907c-8e71dbdcee7b", + "id": "55", "metadata": {}, "source": [ "You can handle **multiple exceptions** at the same time" @@ -861,7 +861,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d92a4bb9-6844-4633-aad8-33cdac070325", + "id": "56", "metadata": { "tags": [] }, @@ -878,7 +878,7 @@ }, { "cell_type": "markdown", - "id": "11357ea4-ff6d-4831-975b-921f7630d37f", + "id": "57", "metadata": { "tags": [] }, @@ -902,7 +902,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5fc9d098-e17f-4ddd-8f32-7e33651d2052", + "id": "58", "metadata": { "tags": [] }, @@ -921,7 +921,7 @@ }, { "cell_type": "markdown", - "id": "295c7eb8-9c74-43f9-ae5c-58e6699d90e6", + "id": "59", "metadata": {}, "source": [ "- We try to open a file called `README.txt`. A `FileNotFoundError` will be raised if it's not found\n", @@ -933,7 +933,7 @@ }, { "cell_type": "markdown", - "id": "3175d392-66b2-4bca-80f9-cf3f45c3a84a", + "id": "60", "metadata": { "tags": [] }, @@ -944,7 +944,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b834570f-965c-4440-9c6e-d713f680c82b", + "id": "61", "metadata": { "tags": [] }, @@ -957,7 +957,7 @@ }, { "cell_type": "markdown", - "id": "26f986e9-dd0e-4445-b6df-73aee64c565b", + "id": "62", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -968,7 +968,7 @@ }, { "cell_type": "markdown", - "id": "c596ee74-776e-4114-b82c-823fc9f8f751", + "id": "63", "metadata": {}, "source": [ "A factor of a positive integer `n` is any positive integer less than or equal to `n` that divides `n` with no remainder.\n", @@ -987,7 +987,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b18485d-ad65-4388-813b-b37832ef255e", + "id": "64", "metadata": { "tags": [] }, @@ -1004,7 +1004,7 @@ }, { "cell_type": "markdown", - "id": "5c2e26a7-31f4-4419-a68d-811da56adfb1", + "id": "65", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1015,7 +1015,7 @@ }, { "cell_type": "markdown", - "id": "e04d871e-16ae-4209-9118-7fdbc1d90d61", + "id": "66", "metadata": {}, "source": [ "Given a list of integers, your task is to complete the code below that finds the pair of numbers in the list that add up to `2020`. The list of numbers is already available as the variable `nums`.\n", @@ -1033,7 +1033,7 @@ }, { "cell_type": "markdown", - "id": "4156c367-e1b8-400c-bb2f-71c812c8ee7a", + "id": "67", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1045,7 +1045,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54360e0e-0867-4acc-8f48-35ca15b37d39", + "id": "68", "metadata": { "tags": [] }, @@ -1062,7 +1062,7 @@ }, { "cell_type": "markdown", - "id": "55055676-4a91-4c45-8db6-b1736a958138", + "id": "69", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1073,7 +1073,7 @@ }, { "cell_type": "markdown", - "id": "44c96dcd-d89d-4073-9e8f-226efd124d99", + "id": "70", "metadata": {}, "source": [ "
\n", @@ -1090,7 +1090,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ae7e92dd-caa2-41ea-9eda-ad2d7a2bf1ad", + "id": "71", "metadata": { "tags": [] }, @@ -1107,7 +1107,7 @@ }, { "cell_type": "markdown", - "id": "cc5d1993-29ab-4e73-911f-61830a220c4e", + "id": "72", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1118,7 +1118,7 @@ }, { "cell_type": "markdown", - "id": "cf68ea90-36ea-4017-8b13-ab90455c5252", + "id": "73", "metadata": {}, "source": [ "You have 100 cats.\n", @@ -1145,7 +1145,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a694a2c2-38de-4576-964e-cc3181d9fa0d", + "id": "74", "metadata": { "tags": [] }, @@ -1162,7 +1162,7 @@ }, { "cell_type": "markdown", - "id": "ef9ce337-7a8b-4766-9593-28edf579fe25", + "id": "75", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1173,7 +1173,7 @@ }, { "cell_type": "markdown", - "id": "ef18383f-235f-420f-9f48-f7de45c94d28", + "id": "76", "metadata": {}, "source": [ "During a winter holidays break, your friends propose to hold a [toboggan](https://en.wikipedia.org/wiki/Toboggan) race. While inspecting the map of the place where you decided to hold the race, you realize that it could be rather dangerous as there are many trees along the slope.\n", @@ -1201,7 +1201,7 @@ }, { "cell_type": "markdown", - "id": "3a4a6a1e-79d0-4ac1-9821-a134dea56b19", + "id": "77", "metadata": {}, "source": [ "#### Part 1 🌶️" @@ -1209,7 +1209,7 @@ }, { "cell_type": "markdown", - "id": "a1b89202-88f3-4758-bffe-c9026ff993d5", + "id": "78", "metadata": {}, "source": [ "
\n", @@ -1220,7 +1220,7 @@ }, { "cell_type": "markdown", - "id": "5d5699be-3d72-4e31-9281-456dd5025297", + "id": "79", "metadata": {}, "source": [ "
\n", @@ -1231,7 +1231,7 @@ }, { "cell_type": "markdown", - "id": "6c528a49-5f30-48ae-9fa5-29bd3e6ff4d7", + "id": "80", "metadata": {}, "source": [ "
\n", @@ -1249,7 +1249,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a01ced11-d8df-4dcb-af5a-c31cc507f5b7", + "id": "81", "metadata": {}, "outputs": [], "source": [ @@ -1287,7 +1287,7 @@ }, { "cell_type": "markdown", - "id": "8ae69510-8756-4c24-b3ec-013fc1c9a621", + "id": "82", "metadata": { "tags": [] }, @@ -1297,7 +1297,7 @@ }, { "cell_type": "markdown", - "id": "d632bbac-f22f-4ede-84db-f8885c27ce30", + "id": "83", "metadata": {}, "source": [ "You check other possible slopes to see if you chose the safest one. These are all the possible slopes according to your map:\n", @@ -1316,7 +1316,7 @@ }, { "cell_type": "markdown", - "id": "c80bdc85-4198-43fc-bf77-bc29406022e8", + "id": "84", "metadata": {}, "source": [ "
\n", @@ -1328,7 +1328,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f39f7b6f-d768-4e8f-ace7-708eee7337a2", + "id": "85", "metadata": {}, "outputs": [], "source": [ diff --git a/functions.ipynb b/functions.ipynb index 77837e84..93504995 100644 --- a/functions.ipynb +++ b/functions.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "d92307e3-d734-4d08-a8dc-ee8a201c3b6e", + "id": "0", "metadata": {}, "source": [ "# Functions" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "c9a51b45-de42-4887-9244-f6cc1d74aa0e", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -56,7 +56,7 @@ }, { "cell_type": "markdown", - "id": "3edb3999-85e2-4cd5-bcfa-67693891bf6f", + "id": "2", "metadata": { "tags": [] }, @@ -66,7 +66,7 @@ }, { "cell_type": "markdown", - "id": "ad4e36dc-2e37-41ca-bc4e-48ea24975fe2", + "id": "3", "metadata": {}, "source": [ "Additional materials where you can find more details about writing functions in Python. For each link, it's indicated if it's a video, a text, or a practical resource.\n", @@ -78,7 +78,7 @@ }, { "cell_type": "markdown", - "id": "00ac8e40-9a6e-4fda-bcd6-ca0b7bb0bfd4", + "id": "4", "metadata": {}, "source": [ "---" @@ -86,7 +86,7 @@ }, { "cell_type": "markdown", - "id": "6787e774-0b23-428a-abe2-b966c1a59047", + "id": "5", "metadata": { "tags": [] }, @@ -100,7 +100,7 @@ }, { "cell_type": "markdown", - "id": "d1e43724-68a1-4fdb-a846-dc1c926d3d4a", + "id": "6", "metadata": {}, "source": [ "1. Functions in Python are blocks of reusable code that perform a specific task.\n", @@ -110,7 +110,7 @@ }, { "cell_type": "markdown", - "id": "d86ccb9a-9544-4db1-a383-e1b1c4f29ee5", + "id": "7", "metadata": { "tags": [] }, @@ -125,7 +125,7 @@ }, { "cell_type": "markdown", - "id": "d97931a5-31fd-494a-8a4a-f62102a6062e", + "id": "8", "metadata": { "tags": [] }, @@ -135,7 +135,7 @@ }, { "cell_type": "markdown", - "id": "2dde8114-7527-49bc-9b2c-de56dd94de9b", + "id": "9", "metadata": {}, "source": [ "A function in Python has three main parts:\n", @@ -147,7 +147,7 @@ }, { "cell_type": "markdown", - "id": "36be5fba-1079-4e48-8115-ce22b10de76e", + "id": "10", "metadata": {}, "source": [ "## Signature\n", @@ -169,7 +169,7 @@ }, { "cell_type": "markdown", - "id": "5579a33e-65d0-4edf-bbc1-14672f6c09a2", + "id": "11", "metadata": {}, "source": [ "---\n", @@ -206,7 +206,7 @@ }, { "cell_type": "markdown", - "id": "e7ef2776-3643-4a44-94fe-6aaa466e5938", + "id": "12", "metadata": {}, "source": [ "## Body\n", @@ -216,7 +216,7 @@ }, { "cell_type": "markdown", - "id": "28265ca7-c247-4040-ad4e-3b1b004542d1", + "id": "13", "metadata": {}, "source": [ "```python\n", @@ -228,7 +228,7 @@ }, { "cell_type": "markdown", - "id": "b40e2fe7-e340-4757-b43c-ee616d7693c8", + "id": "14", "metadata": {}, "source": [ "The function's outputs are indicated by the (reserved) keyword `return`. All functions in Python return a value, even if that value is `None`. If you omit the `return` keyword, Python assumes that the function returns `None`." @@ -236,7 +236,7 @@ }, { "cell_type": "markdown", - "id": "91939086-1d33-43fe-8982-ffbba3d77f07", + "id": "15", "metadata": {}, "source": [ "## Docstrings\n", @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "d5358dfc-df7d-4a6f-9f3a-4e06820e271c", + "id": "16", "metadata": { "tags": [] }, @@ -283,7 +283,7 @@ }, { "cell_type": "markdown", - "id": "4939ebe9-1e3a-4ef8-b4a6-7604c7c243ef", + "id": "17", "metadata": {}, "source": [ "The terms **parameters** and **arguments** are often used interchangeably, but they refer to different things in the context of function calls." @@ -291,7 +291,7 @@ }, { "cell_type": "markdown", - "id": "339553d5-4a61-4242-a369-6993dc78dc35", + "id": "18", "metadata": {}, "source": [ "## Parameters\n", @@ -301,7 +301,7 @@ }, { "cell_type": "markdown", - "id": "7f845593-f20f-4941-869e-3a7dcd624e9e", + "id": "19", "metadata": {}, "source": [ "```python\n", @@ -315,7 +315,7 @@ }, { "cell_type": "markdown", - "id": "79168642-bad5-4bd8-b625-1742669b55e4", + "id": "20", "metadata": {}, "source": [ "## Arguments\n", @@ -332,7 +332,7 @@ }, { "cell_type": "markdown", - "id": "5b5cb5f3-504d-4edb-8c84-98ace0127cde", + "id": "21", "metadata": {}, "source": [ "## Positional arguments\n", @@ -354,7 +354,7 @@ }, { "cell_type": "markdown", - "id": "7433d92d-1614-430d-a452-34ad82bdf924", + "id": "22", "metadata": {}, "source": [ "## Keyword arguments\n", @@ -376,7 +376,7 @@ }, { "cell_type": "markdown", - "id": "c3431b9d-705c-4598-80bd-79e590a0d17d", + "id": "23", "metadata": {}, "source": [ "## Default values\n", @@ -397,7 +397,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0807177a-e2f3-412c-a10d-691a1109f591", + "id": "24", "metadata": { "tags": [] }, @@ -414,7 +414,7 @@ }, { "cell_type": "markdown", - "id": "28ee880e-0ecd-44b1-b9e2-07865a21a7da", + "id": "25", "metadata": {}, "source": [ "---" @@ -423,7 +423,7 @@ { "cell_type": "code", "execution_count": null, - "id": "336848ef-90e1-4149-9640-b22eea872f09", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -432,7 +432,7 @@ }, { "cell_type": "markdown", - "id": "468fad87-0005-4278-ba12-4caf0f43af86", + "id": "27", "metadata": {}, "source": [ "## Exercise 1" @@ -440,7 +440,7 @@ }, { "cell_type": "markdown", - "id": "2779a92e-6aa2-49a4-b950-164fba120edd", + "id": "28", "metadata": {}, "source": [ "Write a Python function called `greet` that takes two parameters: `name` (a string) and `age` (an integer).\n", @@ -455,7 +455,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5212084f-9742-4f29-b3be-132e361eaee6", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -467,7 +467,7 @@ }, { "cell_type": "markdown", - "id": "7f19f0ba-08de-4717-8f08-7255bed0bcfd", + "id": "30", "metadata": {}, "source": [ "## Exercise 2\n", @@ -495,7 +495,7 @@ { "cell_type": "code", "execution_count": null, - "id": "464259d4-dda5-4451-9d1e-50b1c0161b76", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -507,7 +507,7 @@ }, { "cell_type": "markdown", - "id": "8dfdeb76-3592-4b78-9cbc-d41125dc6f20", + "id": "32", "metadata": {}, "source": [ "---" @@ -515,7 +515,7 @@ }, { "cell_type": "markdown", - "id": "dd593351-58d2-4cab-886e-d7f093445bee", + "id": "33", "metadata": { "tags": [] }, @@ -525,7 +525,7 @@ }, { "cell_type": "markdown", - "id": "d1e150ea-588c-4f4a-88b4-3d2fad1c1ce6", + "id": "34", "metadata": { "tags": [] }, @@ -570,7 +570,7 @@ }, { "cell_type": "markdown", - "id": "04747296-7d42-4f8e-b0e4-705593baad3d", + "id": "35", "metadata": { "tags": [] }, @@ -580,7 +580,7 @@ }, { "cell_type": "markdown", - "id": "7819c88f-5881-41ad-b896-66ce9af404fb", + "id": "36", "metadata": {}, "source": [ "The following might seem trivial: could we assign the same variable name to two different values?\n", @@ -633,7 +633,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7d8a1837-c789-4308-a25f-4d9addc0f1f5", + "id": "37", "metadata": { "tags": [] }, @@ -653,7 +653,7 @@ }, { "cell_type": "markdown", - "id": "2a13e84d-d026-49fc-9a9f-6a0f2be72a69", + "id": "38", "metadata": {}, "source": [ "In this example, `x` is a **global** variable and is accessible from anywhere in the program. `x` is also a **local** variable to the `function`, and is accessible from within the function's body.\n", @@ -663,7 +663,7 @@ }, { "cell_type": "markdown", - "id": "6e18100e-7bca-4fbc-979d-9156fda1dc34", + "id": "39", "metadata": {}, "source": [ "The `nonlocal` keyword is used to access a variable in the **nearest enclosing scope** that is **not** global.\n", @@ -675,7 +675,7 @@ }, { "cell_type": "markdown", - "id": "7a33ad56-74b6-4e13-83a4-4301214fceef", + "id": "40", "metadata": {}, "source": [ "Look at the following example:" @@ -683,7 +683,7 @@ }, { "cell_type": "markdown", - "id": "ae5cccb2-356b-4d18-af38-8d07fd2f600a", + "id": "41", "metadata": {}, "source": [ "```python\n", @@ -711,7 +711,7 @@ }, { "cell_type": "markdown", - "id": "abf76e9a-5a61-4458-87be-a582f44c2774", + "id": "42", "metadata": {}, "source": [ "The `global` keyword is used to access a global variable and modify its value from within a function.\n", @@ -722,7 +722,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fa5a2ab0-3594-41da-8c90-5f378efd34ce", + "id": "43", "metadata": { "tags": [] }, @@ -744,7 +744,7 @@ }, { "cell_type": "markdown", - "id": "e2048b56-9338-4284-96ef-5af250a55eb4", + "id": "44", "metadata": {}, "source": [ "Even though you can access and modify variables from different scope, it's not considered a good practice. When a function makes use of `global` or `nonlocal`, or when modifying a mutable type in-place, it's like when a function modifies its own arguments. It's a **side-effect** that should be generally avoided.\n", @@ -754,7 +754,7 @@ }, { "cell_type": "markdown", - "id": "ee1cdfe3-90f0-43ac-852d-01adfc51b60b", + "id": "45", "metadata": {}, "source": [ "# `*args` and `**kwargs`" @@ -762,7 +762,7 @@ }, { "cell_type": "markdown", - "id": "b87faacb-1da9-4e5b-9cd1-0a23d0ce74b8", + "id": "46", "metadata": {}, "source": [ "In the [Basic datatypes](./basic_datatypes.ipynb#Unpacking) section we saw that iterables (tuples and lists) support **unpacking**. You can exploit unpacking to make a **parallel assignment**.\n", @@ -782,7 +782,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7780b91b-c4b1-4213-a8fa-f1802f02df60", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -797,7 +797,7 @@ }, { "cell_type": "markdown", - "id": "349a3646-f40f-4e57-acfa-b9ba01106734", + "id": "48", "metadata": {}, "source": [ "The only difference with unpacking is: all the optional positional arguments are collected by `*args` **in a tuple** and not in a list.\n", @@ -810,7 +810,7 @@ }, { "cell_type": "markdown", - "id": "b0e594f0-8634-4374-b8ea-e1a267ecc126", + "id": "49", "metadata": {}, "source": [ "One importat rule:\n", @@ -838,7 +838,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8f57bff5-86b1-41c5-b4e9-aecf997446ce", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -850,7 +850,7 @@ }, { "cell_type": "markdown", - "id": "2adb773c-38bc-4281-beb6-bc9b1e430ee5", + "id": "51", "metadata": {}, "source": [ "The following **cannot** work\n", @@ -868,7 +868,7 @@ }, { "cell_type": "markdown", - "id": "944a4e00-3a44-4843-946f-94907e985205", + "id": "52", "metadata": {}, "source": [ "Remember that functions' arguments can be either **positional** or **keyword** arguments:" @@ -877,7 +877,7 @@ { "cell_type": "code", "execution_count": null, - "id": "72157f9a-901e-4d05-a968-156ed87c54da", + "id": "53", "metadata": { "tags": [] }, @@ -890,7 +890,7 @@ }, { "cell_type": "markdown", - "id": "29b31a7f-6ad1-484b-984c-e79a3ee7b57a", + "id": "54", "metadata": {}, "source": [ "We can call the function with" @@ -899,7 +899,7 @@ { "cell_type": "code", "execution_count": null, - "id": "641d9390-66aa-417c-b663-0728f9575822", + "id": "55", "metadata": { "tags": [] }, @@ -914,7 +914,7 @@ }, { "cell_type": "markdown", - "id": "3215c24b-fe0a-4324-9469-eaf9f33270b7", + "id": "56", "metadata": {}, "source": [ "After `*args` there can be **no additional positional arguments** but we might have some (or no) keyword arguments.\n", @@ -925,7 +925,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c1d3e823-f201-40ba-9134-e9a0f15c1e8e", + "id": "57", "metadata": { "tags": [] }, @@ -945,7 +945,7 @@ }, { "cell_type": "markdown", - "id": "27a6389a-1d83-45cc-b3e1-19d725823f65", + "id": "58", "metadata": {}, "source": [ "Remember: `d` is a **required** keyword argument because we didn't supply a default value in the function definition.\n", @@ -956,7 +956,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a9c49c52-65db-45eb-896a-e1ffa7e49180", + "id": "59", "metadata": { "tags": [] }, @@ -968,7 +968,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31ed5304-123b-4b82-a43e-3f63377e38d5", + "id": "60", "metadata": { "tags": [] }, @@ -980,7 +980,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5ff3f27b-6752-4467-8ce5-3c11a56cb270", + "id": "61", "metadata": { "tags": [] }, @@ -991,7 +991,7 @@ }, { "cell_type": "markdown", - "id": "fb4c8eb2-efdb-48da-be7f-6ab2d08102ec", + "id": "62", "metadata": {}, "source": [ "We can even **omit** mandatory positional arguments\n", @@ -1008,7 +1008,7 @@ }, { "cell_type": "markdown", - "id": "ae9c9e74-259b-4468-a56a-e1ae1a1debb0", + "id": "63", "metadata": {}, "source": [ "Or we can force **no positional arguments at all**:\n", @@ -1023,7 +1023,7 @@ }, { "cell_type": "markdown", - "id": "c5e934a2-9201-4e03-be47-e2f908937624", + "id": "64", "metadata": {}, "source": [ "You can see that with iterables unpacking and the two `*`/`**` operators, Python is showing all its versatility when it comes to writing your own function.\n", @@ -1036,7 +1036,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f3dee1be-c1bf-4ecb-8dc5-3b83c11f5f91", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -1045,7 +1045,7 @@ }, { "cell_type": "markdown", - "id": "bab6bfa7-58f4-4c38-8ee6-fbff5911e9bb", + "id": "66", "metadata": {}, "source": [ "## Exercise 3\n", @@ -1065,7 +1065,7 @@ { "cell_type": "code", "execution_count": null, - "id": "73472136-0e08-45b6-a51f-755f49c2b46b", + "id": "67", "metadata": {}, "outputs": [], "source": [ @@ -1077,7 +1077,7 @@ }, { "cell_type": "markdown", - "id": "b8e67ba8-61c7-4fe6-8659-27ade39dbe9c", + "id": "68", "metadata": {}, "source": [ "---" @@ -1085,7 +1085,7 @@ }, { "cell_type": "markdown", - "id": "9e2e78c7-6208-47cc-97dc-e1c196346b7c", + "id": "69", "metadata": {}, "source": [ "## Quiz on functions" @@ -1094,7 +1094,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8af7ec62-11bb-44e4-9daa-b7078b2327ba", + "id": "70", "metadata": { "tags": [] }, @@ -1106,7 +1106,7 @@ }, { "cell_type": "markdown", - "id": "e5615c16-7130-4c05-9081-0a495d7090b2", + "id": "71", "metadata": { "tags": [] }, @@ -1122,7 +1122,7 @@ }, { "cell_type": "markdown", - "id": "c30daf6d-1250-4928-8c60-a896506075b7", + "id": "72", "metadata": { "jp-MarkdownHeadingCollapsed": true }, @@ -1132,7 +1132,7 @@ }, { "cell_type": "markdown", - "id": "a680c83c-065a-4ae0-bf6f-fb5084d5c560", + "id": "73", "metadata": { "tags": [] }, @@ -1149,7 +1149,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f6416b66-f094-432b-8589-5e44e0d67388", + "id": "74", "metadata": { "tags": [] }, @@ -1166,7 +1166,7 @@ }, { "cell_type": "markdown", - "id": "ba435a6b-caac-48e2-a0e2-80edabdf1215", + "id": "75", "metadata": { "jp-MarkdownHeadingCollapsed": true }, @@ -1184,7 +1184,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b6e0ee24-8115-4741-acfe-c2938bb40525", + "id": "76", "metadata": { "tags": [] }, @@ -1201,7 +1201,7 @@ }, { "cell_type": "markdown", - "id": "1c93c572-7890-4bd7-a0f6-d4015679df39", + "id": "77", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1212,7 +1212,7 @@ }, { "cell_type": "markdown", - "id": "6a40b25b-fa38-44c8-8a80-d1e86c38ecab", + "id": "78", "metadata": { "tags": [] }, @@ -1222,7 +1222,7 @@ }, { "cell_type": "markdown", - "id": "61fdaa6e-9f5c-4039-a09e-e79146175703", + "id": "79", "metadata": {}, "source": [ "You have a range of numbers `136760-595730` and need to count how many valid password it contains. A valid password must meet **all** the following criteria:\n", @@ -1243,7 +1243,7 @@ }, { "cell_type": "markdown", - "id": "0b4e4131-9137-44a4-9894-8b375f55d6fe", + "id": "80", "metadata": {}, "source": [ "\n", @@ -1254,7 +1254,7 @@ }, { "cell_type": "markdown", - "id": "1c695285-0b1d-4c23-8724-1a85269cb276", + "id": "81", "metadata": {}, "source": [ "\n", @@ -1266,7 +1266,7 @@ { "cell_type": "code", "execution_count": null, - "id": "517f4d43-0ffa-407d-9035-7c8e47b64103", + "id": "82", "metadata": {}, "outputs": [], "source": [ @@ -1281,7 +1281,7 @@ }, { "cell_type": "markdown", - "id": "edac5c6a-23fa-4f09-a462-5682201a449f", + "id": "83", "metadata": { "tags": [] }, @@ -1291,7 +1291,7 @@ }, { "cell_type": "markdown", - "id": "af330663-15c2-48f7-b407-e09cecc62d4d", + "id": "84", "metadata": {}, "source": [ "You have a new rule: **at least** two adjacent matching digits **must not be part of a larger group of matching digits**.\n", @@ -1313,7 +1313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17106c0f-e9df-4888-bb21-e2806cc72df4", + "id": "85", "metadata": {}, "outputs": [], "source": [ @@ -1328,7 +1328,7 @@ }, { "cell_type": "markdown", - "id": "503a18e5-8ee4-4a02-89f9-09cbca3a8e50", + "id": "86", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -1339,7 +1339,7 @@ }, { "cell_type": "markdown", - "id": "957eb5a0-5331-48e3-86b6-7b99299d710f", + "id": "87", "metadata": {}, "source": [ "#### Part 1" @@ -1347,7 +1347,7 @@ }, { "cell_type": "markdown", - "id": "59093ed8-b422-4f97-8ffc-801f6149458a", + "id": "88", "metadata": {}, "source": [ "You have a list of buckets, each containing some items labeled from `a` to `z`, or from `A` to `Z`. Each bucket is split into **two** equally sized compartments.\n", @@ -1378,7 +1378,7 @@ }, { "cell_type": "markdown", - "id": "09122222-0d2e-48f1-8b7b-7d3925dc2a6d", + "id": "89", "metadata": {}, "source": [ "
\n", @@ -1388,7 +1388,7 @@ }, { "cell_type": "markdown", - "id": "e3c00e1d-44e1-45a6-bf1c-68503cd83b01", + "id": "90", "metadata": {}, "source": [ "
\n", @@ -1399,7 +1399,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3eea5fd5-fef2-41ef-93fd-541a332cf679", + "id": "91", "metadata": { "tags": [] }, @@ -1415,7 +1415,7 @@ }, { "cell_type": "markdown", - "id": "1085e791-f1df-4fce-89ae-9c169dbf8aa2", + "id": "92", "metadata": { "jp-MarkdownHeadingCollapsed": true }, @@ -1425,7 +1425,7 @@ }, { "cell_type": "markdown", - "id": "0b68ba01-1a08-43c5-84b2-e73315ab0f53", + "id": "93", "metadata": {}, "source": [ "You are told that you should not care about the priority of **every item**, but only of a \"special item\" that is common to groups of **three buckets**.\n", @@ -1451,7 +1451,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5acf6617-1275-42a0-b656-bfa59d33493b", + "id": "94", "metadata": {}, "outputs": [], "source": [ diff --git a/functions_advanced.ipynb b/functions_advanced.ipynb index 8200ef09..2847558b 100644 --- a/functions_advanced.ipynb +++ b/functions_advanced.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "658fd9eb-ee74-4c01-843a-69985c393c11", + "id": "0", "metadata": {}, "source": [ "# Functions (advanced)" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "f9ad2013-b8f7-4c9c-8ee7-6316a503795b", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -49,7 +49,7 @@ }, { "cell_type": "markdown", - "id": "1e7a4298-0533-43e8-b7d3-2e330edac443", + "id": "2", "metadata": {}, "source": [ "We are going to cover the following topics:\n", @@ -62,7 +62,7 @@ }, { "cell_type": "markdown", - "id": "2b7dac95-e83a-46c6-8ad5-6b55a369bf17", + "id": "3", "metadata": {}, "source": [ "## Recap" @@ -70,7 +70,7 @@ }, { "cell_type": "markdown", - "id": "218acd08-b0f9-4c4f-83d3-613497d17b2e", + "id": "4", "metadata": {}, "source": [ "Before starting our deep dive on functions, we must revise quickly two important concepts. Have a look at the [Functions](./functions.ipynb#The-scope-of-a-function) notebook for more detail.\n", @@ -81,7 +81,7 @@ }, { "cell_type": "markdown", - "id": "b618d311-0e0d-4748-a434-39b5a0a0e585", + "id": "5", "metadata": {}, "source": [ "### Functions are objects" @@ -89,7 +89,7 @@ }, { "cell_type": "markdown", - "id": "380773ce-09de-42c1-8146-2ed3502ddeca", + "id": "6", "metadata": {}, "source": [ "As an example, suppose that we want to create a \"password checker\", that is, a function that can verify if an input password complies with some rules (e.g., minumum length, a given number of special characters). We could create a function with the following signature:\n", @@ -110,7 +110,7 @@ }, { "cell_type": "markdown", - "id": "438649ea-35d6-4404-8250-fa76bc4fda9d", + "id": "7", "metadata": {}, "source": [ "We can instead define a so-called **higher-order function** (see [Functional programming](./functional_programming.ipynb#Higher-Order-Functions-/-Functions-as-Values)): a function that returns another function.\n", @@ -119,7 +119,7 @@ }, { "cell_type": "markdown", - "id": "fc062b73-370e-4fc2-8f51-7237e9022791", + "id": "8", "metadata": {}, "source": [ "```python\n", @@ -144,7 +144,7 @@ }, { "cell_type": "markdown", - "id": "ee874e2b-6f6d-454f-a1c1-f79cc50415a5", + "id": "9", "metadata": {}, "source": [ "You would first call your factory function with some password requirements:\n", @@ -162,7 +162,7 @@ }, { "cell_type": "markdown", - "id": "5d443e29-214b-4b1e-ae50-c1948080ee91", + "id": "10", "metadata": {}, "source": [ "### Scopes and namespaces" @@ -170,7 +170,7 @@ }, { "cell_type": "markdown", - "id": "c76d3dde-eb94-4552-9df7-d0e95d946967", + "id": "11", "metadata": {}, "source": [ "Python's variables are just names (i.e., labels) that we can **bind** to objects. Each variable is simply telling Python where to look in our computer's memory to retrieve some data. These bindings are **not global**: some of them exist only in specific parts of our code.\n", @@ -180,7 +180,7 @@ }, { "cell_type": "markdown", - "id": "ee364526-00d2-40ec-bb33-3478ec3390a0", + "id": "12", "metadata": {}, "source": [ "We always have the following scopes:\n", @@ -194,7 +194,7 @@ }, { "cell_type": "markdown", - "id": "f2654077-9a14-434a-acd6-81ca8b996228", + "id": "13", "metadata": {}, "source": [ "When Python needs to retrieve which object is referenced by a given name, it always starts from the current scope (the `local` one if we are inside a function's body). If a name binding is not found there, it searches in the scope immediately up in the hierarchy.\n", @@ -204,7 +204,7 @@ }, { "cell_type": "markdown", - "id": "c3b21272-45b0-4e21-ae46-8d4deba09164", + "id": "14", "metadata": {}, "source": [ "When Python encounters a function **definition** (i.e., at compile-time), it does two things:\n", @@ -215,7 +215,7 @@ }, { "cell_type": "markdown", - "id": "a43ecf5e-d689-4bd7-8eee-2f1805e191d1", + "id": "15", "metadata": {}, "source": [ "Examples:\n", @@ -241,7 +241,7 @@ }, { "cell_type": "markdown", - "id": "a3de049f-475f-4984-932e-a938dff21106", + "id": "16", "metadata": {}, "source": [ "A function gets its local scope upon calling. Since we can have function definitions inside of other functions, there can be **nested scopes**. This is where the `nonlocal` keyword becomes useful or even needed.\n", @@ -254,7 +254,7 @@ { "cell_type": "code", "execution_count": null, - "id": "394f52d5-3141-4273-9852-dc099d0adcdb", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -279,7 +279,7 @@ }, { "cell_type": "markdown", - "id": "50184808-ee68-4a1e-84a0-ff421074aabe", + "id": "18", "metadata": {}, "source": [ "Two important notes about the `nonlocal` keyword:\n", @@ -290,7 +290,7 @@ }, { "cell_type": "markdown", - "id": "49f00325-11df-402c-a0c9-e2cb8dd091a2", + "id": "19", "metadata": {}, "source": [ "
\n", @@ -300,7 +300,7 @@ }, { "cell_type": "markdown", - "id": "4543c0c9-d6b7-4c48-803d-1d629845fe0b", + "id": "20", "metadata": {}, "source": [ "## Mutable objects as default values of function's parameters" @@ -308,7 +308,7 @@ }, { "cell_type": "markdown", - "id": "ca2ca3de-4cb0-41fc-93ad-d5c38b942a99", + "id": "21", "metadata": {}, "source": [ "Using mutable objects like lists or dictionaries as a function's parameters default values requires extra care, as it can lead to some unexpected or unwanted behaviors.\n", @@ -317,7 +317,7 @@ }, { "cell_type": "markdown", - "id": "992d588c-88c9-4c68-a078-924335fe2e62", + "id": "22", "metadata": {}, "source": [ "Consider what happens when Python evaluates the following code:\n", @@ -337,7 +337,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f610ff20-e5a1-4b15-a3ff-8977ad13dbe7", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -349,7 +349,7 @@ }, { "cell_type": "markdown", - "id": "70572399-3c56-4c14-ac92-519e5bfbc70f", + "id": "24", "metadata": {}, "source": [ "A simple logging function.\n", @@ -359,7 +359,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28d78cfc-68b3-4bb4-ae9d-d2baec4f3ed1", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -372,7 +372,7 @@ }, { "cell_type": "markdown", - "id": "e788532b-a0bc-4b58-b6ae-f6c6a4d0a13a", + "id": "26", "metadata": {}, "source": [ "Something is wrong here: we waited 5 seconds, but the timestamp of our log message **did not change**.\n", @@ -381,7 +381,7 @@ }, { "cell_type": "markdown", - "id": "6b2b6299-4a8b-4f2a-8bf1-b1e1024b6f83", + "id": "27", "metadata": {}, "source": [ "The correct pattern to avoid this unwanted behavior is setting a default value of `None`, so that the argument remains optional.\n", @@ -391,7 +391,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4ee7af02-a935-425a-b57a-c6a747758d30", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -403,7 +403,7 @@ { "cell_type": "code", "execution_count": null, - "id": "80584b4f-978c-4153-9ff9-10183225139a", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -414,7 +414,7 @@ }, { "cell_type": "markdown", - "id": "3174d7ae-6353-4561-b691-83b7fc729cae", + "id": "30", "metadata": {}, "source": [ "Now the output is what we expected." @@ -422,7 +422,7 @@ }, { "cell_type": "markdown", - "id": "fbcf8f91-86d5-404f-ab46-8a159a9ec18f", + "id": "31", "metadata": {}, "source": [ "Another problematic context is when we're dealing with **mutable objects** (e.g., lists, sets, dictionaries).\n", @@ -435,7 +435,7 @@ { "cell_type": "code", "execution_count": null, - "id": "81c0cdff-32fc-4c6f-9072-f7a236c957ec", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -446,7 +446,7 @@ }, { "cell_type": "markdown", - "id": "195ce01b-363f-45de-8af5-02ec542b88c7", + "id": "33", "metadata": {}, "source": [ "We now have two stores and want to add some items to them:" @@ -455,7 +455,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9a88b5de-c0fe-42e8-a103-4ba5b24943b5", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -471,7 +471,7 @@ }, { "cell_type": "markdown", - "id": "428ba9cb-bc96-4b6c-b5a3-c9b3ba483a69", + "id": "35", "metadata": {}, "source": [ "All good.\n", @@ -482,7 +482,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47bb8773-dd5a-4836-8c5b-8e66fcae92e3", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -494,7 +494,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ba49b5b4-7127-40f7-b19c-53cd197cc693", + "id": "37", "metadata": {}, "outputs": [], "source": [ @@ -506,7 +506,7 @@ }, { "cell_type": "markdown", - "id": "20f49218-9fa5-48b7-b21a-535cfbeb2810", + "id": "38", "metadata": {}, "source": [ "Okay, all good.\n", @@ -516,7 +516,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b5044e41-7c41-469b-974d-6b5f7f052b61", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -527,7 +527,7 @@ }, { "cell_type": "markdown", - "id": "a132eb6b-7b4d-436c-925a-7e504ab6d4f0", + "id": "40", "metadata": {}, "source": [ "Again, not what we expected, right?\n", @@ -539,7 +539,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bf6937c7-633c-45e7-9220-ecf3b8bade12", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -553,7 +553,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ffc972b4-2c29-4362-8564-0f260f33b242", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -564,7 +564,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e6dbd7f2-1e44-489c-bbcc-0e6704c27fb4", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -574,7 +574,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b6d27cda-6795-4421-b917-cfae946b5713", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -584,7 +584,7 @@ }, { "cell_type": "markdown", - "id": "3e5f9f9f-c57b-4b85-bb29-ff56d739e06e", + "id": "45", "metadata": {}, "source": [ "And now everything works as we expected." @@ -592,7 +592,7 @@ }, { "cell_type": "markdown", - "id": "9c458327-b5bd-4df6-8025-d54ec60edeaa", + "id": "46", "metadata": {}, "source": [ "Using mutable objects as default values usually lead to unwanted results.\n", @@ -604,7 +604,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5d88ed0c-5e32-4db1-aebc-e066891a8f47", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -619,7 +619,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3c9ba891-accc-446c-bf67-b06146411470", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -629,7 +629,7 @@ { "cell_type": "code", "execution_count": null, - "id": "93ba1699-67e1-4c08-a321-077d2354e0d4", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -638,7 +638,7 @@ }, { "cell_type": "markdown", - "id": "69cdf435-23fb-419e-9746-dd5a29bc40e4", + "id": "50", "metadata": {}, "source": [ "We had to recalculate some values the second time, values that we could have saved for any subsequent call.\n", @@ -648,7 +648,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9955eba2-62dc-445b-bf16-25f81fd02581", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -667,7 +667,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a77781a1-5bd7-4e2e-8863-a5d1e92ba72a", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -677,7 +677,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dd3120ab-4ad3-46c3-9302-b4a9e20fc137", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -687,7 +687,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b919b438-63e6-4869-8bc0-86eee0ea7b54", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -696,7 +696,7 @@ }, { "cell_type": "markdown", - "id": "e5e6276e-1674-4b9a-8da2-5dffbaf1e09a", + "id": "55", "metadata": {}, "source": [ "Since the dictionary `cache` is initialized as an empty `dict()` **at compile-time** (when we define the function), we can update its content in any subsequent call to `factorial`.\n", @@ -705,7 +705,7 @@ }, { "cell_type": "markdown", - "id": "6cdafe9c-2448-4ba2-b351-98de62508d4f", + "id": "56", "metadata": {}, "source": [ "## Lambdas" @@ -713,7 +713,7 @@ }, { "cell_type": "markdown", - "id": "e1bf04d6-c294-4143-bc9a-c647c930a934", + "id": "57", "metadata": {}, "source": [ "We already now how to create a function: we use the `def` keyword:\n", @@ -726,7 +726,7 @@ }, { "cell_type": "markdown", - "id": "633b0bfa-1f64-4e3e-a100-82c148a13ff6", + "id": "58", "metadata": {}, "source": [ "A function can have **parameters** and a `return` statement.\n", @@ -735,7 +735,7 @@ }, { "cell_type": "markdown", - "id": "c4aa553c-a309-4f5d-be37-0f4ab0d9176d", + "id": "59", "metadata": {}, "source": [ "There's another way to define a function object: with **lambda expressions** (or lambdas).\n", @@ -755,7 +755,7 @@ }, { "cell_type": "markdown", - "id": "c515caf1-0a60-4fcd-9dd7-3596ab834e21", + "id": "60", "metadata": {}, "source": [ "Lambdas are objects, as much as functions are, so we can define a lambda and assign it to a name:" @@ -764,7 +764,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7266f0f2-cc8f-4326-b436-cce3512f992b", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -774,7 +774,7 @@ { "cell_type": "code", "execution_count": null, - "id": "767cc544-5153-4472-973a-dc607f78558f", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -783,7 +783,7 @@ }, { "cell_type": "markdown", - "id": "ec0dea2c-e714-44dc-9334-a2fe58debf0c", + "id": "63", "metadata": {}, "source": [ "We can also define lambdas with parameters **with a default value**:" @@ -792,7 +792,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e8681478-f223-4e7c-8d67-ad42da7aff20", + "id": "64", "metadata": {}, "outputs": [], "source": [ @@ -802,7 +802,7 @@ { "cell_type": "code", "execution_count": null, - "id": "efb414e2-f002-4b46-8ee0-bc8d980235ca", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -812,7 +812,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41acbdfa-a3a9-47e8-9343-69e60365a085", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -821,7 +821,7 @@ }, { "cell_type": "markdown", - "id": "6742a7f5-c214-4ccb-9a4c-2e5d882f7de6", + "id": "67", "metadata": {}, "source": [ "Lambdas are very handy when we need something that behaves like a function, but we don't plan to use it many times. Examples:\n", @@ -837,7 +837,7 @@ }, { "cell_type": "markdown", - "id": "96f87d21-5e7f-408f-aa6c-c15929cca11e", + "id": "68", "metadata": {}, "source": [ "Lambdas are **anonymous function objects**." @@ -846,7 +846,7 @@ { "cell_type": "code", "execution_count": null, - "id": "961f2782-38ab-4a7d-9a4d-6e9d43801827", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -855,7 +855,7 @@ }, { "cell_type": "markdown", - "id": "f62922e3-9809-4205-b875-06c793003e89", + "id": "70", "metadata": {}, "source": [ "Since are objects, they can be passed to (or returned from) other functions:" @@ -864,7 +864,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fa3eb3c3-9933-453a-8e59-27dc79ccc34f", + "id": "71", "metadata": {}, "outputs": [], "source": [ @@ -875,7 +875,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4eeb04fe-d544-48ef-a77b-2f145e720236", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -885,7 +885,7 @@ { "cell_type": "code", "execution_count": null, - "id": "505718d0-7079-4869-b855-811add5d4e6e", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -894,7 +894,7 @@ }, { "cell_type": "markdown", - "id": "39da23ba-fead-49de-bd27-43ac6cfd019f", + "id": "74", "metadata": {}, "source": [ "The previous example is **not** the suggested way to sum values of an iterable: we should use the built-in `sum()` when appropriate:" @@ -903,7 +903,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9636ece4-fe53-47eb-a4a3-fd9ccee6cc76", + "id": "75", "metadata": {}, "outputs": [], "source": [ @@ -913,7 +913,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7de26d22-e493-4c87-9d1d-d5866f243149", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -922,7 +922,7 @@ }, { "cell_type": "markdown", - "id": "0a22c386-b830-4038-8930-ccc172137e6f", + "id": "77", "metadata": {}, "source": [ "### Lambdas and sorting" @@ -930,7 +930,7 @@ }, { "cell_type": "markdown", - "id": "d646f3b7-9d6c-48bd-993a-df4b58703d78", + "id": "78", "metadata": {}, "source": [ "Python has a built-in `sorted` method returns any iterable sorted according to a default ordering.\n", @@ -940,7 +940,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3c4b63b7-5e14-4dca-a12d-3cddf9ae3d5d", + "id": "79", "metadata": {}, "outputs": [], "source": [ @@ -950,7 +950,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fa77063b-852f-4bd3-a3c3-d06e0acf41fc", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -959,7 +959,7 @@ }, { "cell_type": "markdown", - "id": "e3230390-88d4-45d1-ba88-fda0cd284d2a", + "id": "81", "metadata": {}, "source": [ "Python's `sorted` has a keyword-only argument named `key=` that takes a function used to return the key – that is, the ordinal criteria according to which we want to sort the iterable." @@ -968,7 +968,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dcded938-a811-4c9b-9754-f0ecbbb54c19", + "id": "82", "metadata": {}, "outputs": [], "source": [ @@ -977,7 +977,7 @@ }, { "cell_type": "markdown", - "id": "dded89fa-3d95-4e66-8320-0f4b1137dff7", + "id": "83", "metadata": {}, "source": [ "Let's see how we can created a \"sorted dictionary\".\n", @@ -990,7 +990,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f9c0fd39-09be-4326-9bdd-57dfeaa8ab97", + "id": "84", "metadata": {}, "outputs": [], "source": [ @@ -1000,7 +1000,7 @@ }, { "cell_type": "markdown", - "id": "fa44023f-406e-4bfe-8f84-8731ea68edd7", + "id": "85", "metadata": {}, "source": [ "Iterating over a dictionary is equivalent to iterate **over keys**.\n", @@ -1010,7 +1010,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1cefc1c7-190d-4a32-9ecb-851315b6f6d5", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -1019,7 +1019,7 @@ }, { "cell_type": "markdown", - "id": "7d0882a6-a8a7-4687-9bfd-0d96476d348a", + "id": "87", "metadata": {}, "source": [ "But wait: now we lost our values!\n", @@ -1029,7 +1029,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e0b14481-087b-4431-a146-7511e3a8bc7c", + "id": "88", "metadata": {}, "outputs": [], "source": [ @@ -1038,7 +1038,7 @@ }, { "cell_type": "markdown", - "id": "421950b6-55da-42f6-91b4-5395a681fb6b", + "id": "89", "metadata": {}, "source": [ "Another useful application of lambdas is when Python doesn't know how to apply an ordering to some kind of data.\n", @@ -1048,7 +1048,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e92b884c-e9f5-42ff-819d-bad7694b2999", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1058,7 +1058,7 @@ { "cell_type": "code", "execution_count": null, - "id": "850758c1-e616-4eaf-b99d-aea169da0359", + "id": "91", "metadata": {}, "outputs": [], "source": [ @@ -1067,7 +1067,7 @@ }, { "cell_type": "markdown", - "id": "703ea9e5-72f3-4eaf-95cd-a579e186bd01", + "id": "92", "metadata": {}, "source": [ "We can sort complex numbers based on their modulus:" @@ -1076,7 +1076,7 @@ { "cell_type": "code", "execution_count": null, - "id": "68923fed-b32d-4cd0-a58b-424a9a8f5d9f", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1085,7 +1085,7 @@ }, { "cell_type": "markdown", - "id": "e8475bd0-9d51-40b1-99d2-0a61038124f6", + "id": "94", "metadata": {}, "source": [ "
\n", @@ -1095,7 +1095,7 @@ }, { "cell_type": "markdown", - "id": "1e906839-6146-4943-a61d-258de87ae279", + "id": "95", "metadata": {}, "source": [ "
\n", @@ -1105,7 +1105,7 @@ }, { "cell_type": "markdown", - "id": "f3613b0b-eb09-4152-954f-bddd92fdb7f4", + "id": "96", "metadata": {}, "source": [ "## Closures" @@ -1113,7 +1113,7 @@ }, { "cell_type": "markdown", - "id": "1e72d59a-2a74-4502-acbe-6fc9ac3ff3aa", + "id": "97", "metadata": {}, "source": [ "Let's consider the following code:" @@ -1122,7 +1122,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2aefd3ca-cb6d-463a-88be-05c89c7dc112", + "id": "98", "metadata": {}, "outputs": [], "source": [ @@ -1139,7 +1139,7 @@ }, { "cell_type": "markdown", - "id": "9afd7b80-4b96-4879-ba7b-7bc36f727a0d", + "id": "99", "metadata": {}, "source": [ "Here the `lang` variable is **non-local** to `inner()` because it's only referenced. `lang` is also called **free variable**.\n", @@ -1152,7 +1152,7 @@ }, { "cell_type": "markdown", - "id": "a4b00d4c-dc4d-4550-bbcd-07a15f9aa7d2", + "id": "100", "metadata": {}, "source": [ "Let's make a small adjustment that will change a lot of things:" @@ -1161,7 +1161,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a9efa784-f542-41aa-9879-18452b77a1e2", + "id": "101", "metadata": {}, "outputs": [], "source": [ @@ -1178,7 +1178,7 @@ }, { "cell_type": "markdown", - "id": "717f601a-eefc-4303-be9b-2b66613eed39", + "id": "102", "metadata": {}, "source": [ "We turned `outer()` into an higher-order function that does not return a simple function, but a closure (`inner()` + the free variable).\n", @@ -1189,7 +1189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "550b55d7-8055-446b-ab9c-1245818c3aa7", + "id": "103", "metadata": {}, "outputs": [], "source": [ @@ -1198,7 +1198,7 @@ }, { "cell_type": "markdown", - "id": "e19c9332-80a4-4771-ae05-4b744d718543", + "id": "104", "metadata": {}, "source": [ "And then call that function as any other function:" @@ -1207,7 +1207,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7a58ef5c-3dc9-4a28-b01e-0128ef4232a1", + "id": "105", "metadata": {}, "outputs": [], "source": [ @@ -1216,7 +1216,7 @@ }, { "cell_type": "markdown", - "id": "7d753841-49d6-4656-b4b9-d16e2a3cb107", + "id": "106", "metadata": {}, "source": [ "But wait a second! How's that possible? 🤔\n", @@ -1229,7 +1229,7 @@ }, { "cell_type": "markdown", - "id": "402bd5c1-af47-4716-baa0-ac60da76efce", + "id": "107", "metadata": {}, "source": [ "If we look once again to the example above, we see that the name `lang` is **shared** between the local scope of `outer()` and the `print` statement inside `inner()`.\n", @@ -1239,7 +1239,7 @@ }, { "cell_type": "markdown", - "id": "0b1977a3-2854-4015-a5d9-6fd066b89e85", + "id": "108", "metadata": {}, "source": [ "![](./images/cell_object.png)" @@ -1247,7 +1247,7 @@ }, { "cell_type": "markdown", - "id": "8f1015aa-ad47-4be6-8612-f9de5ee22e6b", + "id": "109", "metadata": {}, "source": [ "We can see all that by inspecting some _hidden_ attributes of `fn`:" @@ -1256,7 +1256,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22189979-698f-4813-8bff-c70fd83d5a8d", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1266,7 +1266,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2a304bcc-100a-464e-81e1-74355d65d8bf", + "id": "111", "metadata": {}, "outputs": [], "source": [ @@ -1275,7 +1275,7 @@ }, { "cell_type": "markdown", - "id": "0d18060e-78d7-42e3-8e0c-984e3e5f6dcc", + "id": "112", "metadata": {}, "source": [ "We can see now the reason why we can call `fn()` and see the string \"Python rocks!\" printed although the variable `lang` is now out of scope (it's been destroyed).\n", @@ -1285,7 +1285,7 @@ }, { "cell_type": "markdown", - "id": "6d84832a-a780-4439-bacf-4c45615563f5", + "id": "113", "metadata": {}, "source": [ "### Modifying the free variable" @@ -1293,7 +1293,7 @@ }, { "cell_type": "markdown", - "id": "06ee4be4-170b-490b-b17a-0e60b0d9d252", + "id": "114", "metadata": {}, "source": [ "We know that the `nonlocal` keyword allows us to modify variables from the **enclosing scope**. Therefore, the following closure will work as expected:" @@ -1302,7 +1302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12eb4f64-93bd-4a99-804c-386f8e10b048", + "id": "115", "metadata": {}, "outputs": [], "source": [ @@ -1322,7 +1322,7 @@ }, { "cell_type": "markdown", - "id": "7cdf2e9e-1551-4ebe-88c9-796dfd8fc937", + "id": "116", "metadata": {}, "source": [ "The `inc()` function and the `count` variable are the closure, but the `count` variable is not only accessed, but also modified." @@ -1330,7 +1330,7 @@ }, { "cell_type": "markdown", - "id": "d209f602-2ff7-497c-9c4f-a3c419f38da7", + "id": "117", "metadata": {}, "source": [ "We can also have multiple closures that reference (and modify) the same free variable:" @@ -1339,7 +1339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "377e42f8-c05e-4982-aa9c-fd6bef43e91d", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1364,7 +1364,7 @@ { "cell_type": "code", "execution_count": null, - "id": "94937713-746a-4d50-8e06-1772c94a89ff", + "id": "119", "metadata": {}, "outputs": [], "source": [ @@ -1374,7 +1374,7 @@ { "cell_type": "code", "execution_count": null, - "id": "565ea9d9-6e9d-40b4-9450-c765bc747985", + "id": "120", "metadata": {}, "outputs": [], "source": [ @@ -1383,7 +1383,7 @@ }, { "cell_type": "markdown", - "id": "8ed30e46-85b7-4b80-bf20-a2339d5d9509", + "id": "121", "metadata": {}, "source": [ "### Multiple instances of closures" @@ -1391,7 +1391,7 @@ }, { "cell_type": "markdown", - "id": "b9055daa-be56-41b0-97c4-44d33deda357", + "id": "122", "metadata": {}, "source": [ "As we saw before when talking about scopes, every time a function is **called** a new **local scope** is created.\n", @@ -1403,7 +1403,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c55535ac-d32a-491f-9509-423a5b4557b2", + "id": "123", "metadata": {}, "outputs": [], "source": [ @@ -1416,7 +1416,7 @@ }, { "cell_type": "markdown", - "id": "6bdc2d9a-0cc5-4dba-88b4-a942408ffa6c", + "id": "124", "metadata": {}, "source": [ "`n` is our free variable, and we have a closure that contains the function `op()` and the free variable." @@ -1425,7 +1425,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e4bfdffb-b059-4d50-ac96-53638b238314", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1436,7 +1436,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c573a1e0-ab96-4292-a02d-6cdfbeb886db", + "id": "126", "metadata": {}, "outputs": [], "source": [ @@ -1446,7 +1446,7 @@ }, { "cell_type": "markdown", - "id": "806c43d9-c78c-4fd0-9f9a-ec6cbbfa34ba", + "id": "127", "metadata": {}, "source": [ "We can verify that the two closures are completely different even though they were created from the same `power()`:" @@ -1455,7 +1455,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6667349a-6efc-4d22-8709-865c0caf2320", + "id": "128", "metadata": {}, "outputs": [], "source": [ @@ -1465,7 +1465,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c708373c-9439-4a7b-8953-7f87e6309271", + "id": "129", "metadata": {}, "outputs": [], "source": [ @@ -1474,7 +1474,7 @@ }, { "cell_type": "markdown", - "id": "7490f47f-e0a6-42c3-a56f-59503703e200", + "id": "130", "metadata": {}, "source": [ "As we expected, the free variable `n` (of type `int`) is referenced by the cell objects of both closures.\n", @@ -1483,7 +1483,7 @@ }, { "cell_type": "markdown", - "id": "5fe10082-37a7-4d69-a5d1-839dd63050f5", + "id": "131", "metadata": {}, "source": [ "### Closures can be tricky" @@ -1491,7 +1491,7 @@ }, { "cell_type": "markdown", - "id": "2e7d1a9a-04f8-4e4e-a667-391b4e722708", + "id": "132", "metadata": {}, "source": [ "One important aspect of closures can be the source of nasty bugs if we don't understand it well.\n", @@ -1501,7 +1501,7 @@ }, { "cell_type": "markdown", - "id": "9186f397-d07c-4a2c-9de4-9a6df15fb0e9", + "id": "133", "metadata": {}, "source": [ "Let's say we want to create a function to sum different factors to an arbitrary number.\n", @@ -1511,7 +1511,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c0988d39-7321-49d5-a619-0f960c5e352b", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -1524,7 +1524,7 @@ { "cell_type": "code", "execution_count": null, - "id": "466b3e15-6fd4-4643-bf1b-b161bba237b2", + "id": "135", "metadata": {}, "outputs": [], "source": [ @@ -1535,7 +1535,7 @@ }, { "cell_type": "markdown", - "id": "e446d1fc-a129-4fd9-81b1-1142fa99d865", + "id": "136", "metadata": {}, "source": [ "This works as expected:" @@ -1544,7 +1544,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb6d0536-14f4-4399-91ac-d31e23412ad2", + "id": "137", "metadata": {}, "outputs": [], "source": [ @@ -1553,7 +1553,7 @@ }, { "cell_type": "markdown", - "id": "73753cb3-edb3-4dac-be9c-9cb850b9f945", + "id": "138", "metadata": {}, "source": [ "Now we have the following idea to improve our code:" @@ -1562,7 +1562,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1af7eb21-c379-4a86-be7b-4278ca5a4b81", + "id": "139", "metadata": {}, "outputs": [], "source": [ @@ -1578,7 +1578,7 @@ { "cell_type": "code", "execution_count": null, - "id": "984491cc-a6f6-4bef-a8cf-83cc151fc2bf", + "id": "140", "metadata": {}, "outputs": [], "source": [ @@ -1587,7 +1587,7 @@ }, { "cell_type": "markdown", - "id": "6fecef03-780c-49a0-85be-f44378f3936c", + "id": "141", "metadata": {}, "source": [ "We have now 4 functions in the `adders` list:" @@ -1596,7 +1596,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c27ceb4c-53dd-4c0e-8384-a879d28ed0b6", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -1605,7 +1605,7 @@ }, { "cell_type": "markdown", - "id": "980694ef-8baf-4d6a-8908-4bb839717706", + "id": "143", "metadata": {}, "source": [ "Let's see what happens when we call them:" @@ -1614,7 +1614,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a1277798-7a02-4c67-8f77-ee86eb460134", + "id": "144", "metadata": {}, "outputs": [], "source": [ @@ -1623,7 +1623,7 @@ }, { "cell_type": "markdown", - "id": "4dedb6df-c484-4a98-afb8-f95b5ff2d980", + "id": "145", "metadata": {}, "source": [ "Wait, why?! It seems that we picked up the **same value** of the free variable.\n", @@ -1633,7 +1633,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b05043cf-3a6e-4243-a0a5-ea98d4fa0358", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -1642,7 +1642,7 @@ }, { "cell_type": "markdown", - "id": "2e6cd006-ebd2-4191-902d-f88cbd0c51fb", + "id": "147", "metadata": {}, "source": [ "And we can indeed verify that its value referenced by each closure is exactly the same:" @@ -1651,7 +1651,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f056d992-d712-46d8-933d-c6cb8fc276da", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -1660,7 +1660,7 @@ }, { "cell_type": "markdown", - "id": "5f7124e3-856e-4e7f-a71d-e7e3a4198804", + "id": "149", "metadata": {}, "source": [ "Which value? The last iteration of our loop, `n=4`.\n", @@ -1670,7 +1670,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0f90363f-b29a-4829-801d-9eaf681801e2", + "id": "150", "metadata": {}, "outputs": [], "source": [ @@ -1679,7 +1679,7 @@ }, { "cell_type": "markdown", - "id": "18300b91-bcfc-43db-a2a0-61ffe9c61816", + "id": "151", "metadata": {}, "source": [ "The key to understand this behavior is remembering that **closures captures _variables_ and not _values_**.\n", @@ -1691,7 +1691,7 @@ }, { "cell_type": "markdown", - "id": "c3bc9c11-2691-4de9-84ed-49bdc9bfff17", + "id": "152", "metadata": {}, "source": [ "If we wanted to fix the example as we intended, we need to capture the **current** value of `n` when defining the closure:" @@ -1700,7 +1700,7 @@ { "cell_type": "code", "execution_count": null, - "id": "635e47e3-2043-44b2-b452-295a933b43dc", + "id": "153", "metadata": {}, "outputs": [], "source": [ @@ -1716,7 +1716,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bfc73083-d4d7-4a41-94d3-b1a46f37acec", + "id": "154", "metadata": {}, "outputs": [], "source": [ @@ -1726,7 +1726,7 @@ { "cell_type": "code", "execution_count": null, - "id": "98f957a1-b04a-4529-8876-d5fa60917186", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -1735,7 +1735,7 @@ }, { "cell_type": "markdown", - "id": "ed3b46d3-aade-4b31-bfdd-b03b9916ef23", + "id": "156", "metadata": {}, "source": [ "Now, let's inspect our correct closures:" @@ -1744,7 +1744,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8fc351e4-847d-470f-9a5d-0c74f6e5eeb2", + "id": "157", "metadata": {}, "outputs": [], "source": [ @@ -1753,7 +1753,7 @@ }, { "cell_type": "markdown", - "id": "ac143f81-4aae-49ad-950d-9ca092361bda", + "id": "158", "metadata": {}, "source": [ "Hey, why `None`? Let's check our free variable:" @@ -1762,7 +1762,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9f0719f3-bc41-4d42-b633-fa49bf501cc5", + "id": "159", "metadata": {}, "outputs": [], "source": [ @@ -1771,7 +1771,7 @@ }, { "cell_type": "markdown", - "id": "0cfd31d5-b83a-439b-9690-4fbd1fe20b3d", + "id": "160", "metadata": {}, "source": [ "Nothing yet?\n", @@ -1780,7 +1780,7 @@ }, { "cell_type": "markdown", - "id": "b0563fc3-de7b-439a-9a23-07af7d1dff03", + "id": "161", "metadata": {}, "source": [ "
\n", @@ -1791,7 +1791,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20cadf44-2207-4c16-95c4-f3eed8ef19db", + "id": "162", "metadata": {}, "outputs": [], "source": [ @@ -1801,7 +1801,7 @@ }, { "cell_type": "markdown", - "id": "ac01ce82-7dbf-42fb-8d78-69c1a8f34740", + "id": "163", "metadata": {}, "source": [ "### Nested closures" @@ -1809,7 +1809,7 @@ }, { "cell_type": "markdown", - "id": "a7751b1d-0b4e-418c-abab-efac075436f3", + "id": "164", "metadata": {}, "source": [ "We can also nest closures, as much as we can nest functions:" @@ -1818,7 +1818,7 @@ { "cell_type": "code", "execution_count": null, - "id": "eebd35bd-8e14-41a1-9df0-a4c716bc31ff", + "id": "165", "metadata": {}, "outputs": [], "source": [ @@ -1837,7 +1837,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9a08d1c9-d201-4dc0-ad8a-7e6cb1805f77", + "id": "166", "metadata": {}, "outputs": [], "source": [ @@ -1847,7 +1847,7 @@ }, { "cell_type": "markdown", - "id": "be996408-4438-493e-8549-13c212e442db", + "id": "167", "metadata": {}, "source": [ "We create an incrementer function with the default increment, `n=2`, starting from `100`:" @@ -1856,7 +1856,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3754bf22-54f8-4960-b591-b7ed1a6df33d", + "id": "168", "metadata": {}, "outputs": [], "source": [ @@ -1866,7 +1866,7 @@ }, { "cell_type": "markdown", - "id": "b00c8f22-a319-4e7f-b0e9-1c9a41fe2bbd", + "id": "169", "metadata": {}, "source": [ "We can also create another _custom_ incrementer with a different increment value:" @@ -1875,7 +1875,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9d4443b1-c814-4c69-912a-9dadba8955a9", + "id": "170", "metadata": {}, "outputs": [], "source": [ @@ -1885,7 +1885,7 @@ }, { "cell_type": "markdown", - "id": "dd0f62cc-da51-413d-bc0b-4b456abdd824", + "id": "171", "metadata": {}, "source": [ "### Closures: examples" @@ -1893,7 +1893,7 @@ }, { "cell_type": "markdown", - "id": "2b5c88fa-9a60-4286-b526-38a7294d433d", + "id": "172", "metadata": {}, "source": [ "#### Example 1" @@ -1901,7 +1901,7 @@ }, { "cell_type": "markdown", - "id": "69343a4d-aa85-46db-8194-80e64b2a8f2e", + "id": "173", "metadata": {}, "source": [ "Let's see a practical example of using closures.\n", @@ -1914,7 +1914,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f9202909-547f-40df-8cf7-c897045d0865", + "id": "174", "metadata": {}, "outputs": [], "source": [ @@ -1932,7 +1932,7 @@ { "cell_type": "code", "execution_count": null, - "id": "610e83ce-e2f1-430f-9bac-86c1449d637a", + "id": "175", "metadata": {}, "outputs": [], "source": [ @@ -1942,7 +1942,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ac4095a4-7dac-44c2-bd0d-4a40c55fc3eb", + "id": "176", "metadata": {}, "outputs": [], "source": [ @@ -1952,7 +1952,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bad7b335-796d-443d-9bbd-13ce2bb5cd68", + "id": "177", "metadata": {}, "outputs": [], "source": [ @@ -1961,7 +1961,7 @@ }, { "cell_type": "markdown", - "id": "d744a1c6-22c1-4616-b663-b19fb75ef0de", + "id": "178", "metadata": {}, "source": [ "How can we rewrite the our class as a closure?\n", @@ -1971,7 +1971,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ce547faa-4b3a-4c91-b005-a79d8f0f8191", + "id": "179", "metadata": {}, "outputs": [], "source": [ @@ -1988,7 +1988,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54a62857-e94d-4247-805c-f041143e7ef6", + "id": "180", "metadata": {}, "outputs": [], "source": [ @@ -1998,7 +1998,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b91fa945-ca65-4266-ac7d-7e9da458a8dd", + "id": "181", "metadata": {}, "outputs": [], "source": [ @@ -2008,7 +2008,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2f7eced0-7ee1-47d1-9c3b-32e9c19a25df", + "id": "182", "metadata": {}, "outputs": [], "source": [ @@ -2018,7 +2018,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9ffd05c2-45b9-40a3-b38f-e781164c6a27", + "id": "183", "metadata": {}, "outputs": [], "source": [ @@ -2027,7 +2027,7 @@ }, { "cell_type": "markdown", - "id": "29e37eeb-cc17-4d5d-9803-425c6d399d4b", + "id": "184", "metadata": {}, "source": [ "We can make it better: instead of accumulating all the numbers in a list, we only need to keep a running total and count." @@ -2036,7 +2036,7 @@ { "cell_type": "code", "execution_count": null, - "id": "253d0e95-1b33-42d9-88c0-95c6a10cb7df", + "id": "185", "metadata": {}, "outputs": [], "source": [ @@ -2058,7 +2058,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2cadaf0b-04fd-4210-b92b-f17708e1cd23", + "id": "186", "metadata": {}, "outputs": [], "source": [ @@ -2068,7 +2068,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e5ad1f57-b8f5-462d-b5f2-0aa28d4274ad", + "id": "187", "metadata": {}, "outputs": [], "source": [ @@ -2078,7 +2078,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37e5be30-718e-485a-b60f-d8fa1ab8f47f", + "id": "188", "metadata": {}, "outputs": [], "source": [ @@ -2087,7 +2087,7 @@ }, { "cell_type": "markdown", - "id": "5e63c686-923f-4b83-9081-d3cbbde42d68", + "id": "189", "metadata": {}, "source": [ "#### Example 2" @@ -2095,7 +2095,7 @@ }, { "cell_type": "markdown", - "id": "4b52912f-bcfd-4eab-98df-8a09af454415", + "id": "190", "metadata": {}, "source": [ "We want to create a counter function, that is, a function that increments a variable every time it's called:" @@ -2104,7 +2104,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3faacb42-febc-4175-a0d6-634c00af9def", + "id": "191", "metadata": {}, "outputs": [], "source": [ @@ -2119,7 +2119,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb73542b-1949-4290-9a50-13018f97a5d8", + "id": "192", "metadata": {}, "outputs": [], "source": [ @@ -2130,7 +2130,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f0044533-5a6b-43de-afc0-baa37dd2a0ab", + "id": "193", "metadata": {}, "outputs": [], "source": [ @@ -2140,7 +2140,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ca113b53-d223-40a6-a291-c5e30c33c860", + "id": "194", "metadata": {}, "outputs": [], "source": [ @@ -2150,7 +2150,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4a14adc4-2d99-47a2-8c3a-19d6d4d3cec1", + "id": "195", "metadata": {}, "outputs": [], "source": [ @@ -2160,7 +2160,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cc144f72-dd32-4889-a864-4d854d322e97", + "id": "196", "metadata": {}, "outputs": [], "source": [ @@ -2169,7 +2169,7 @@ }, { "cell_type": "markdown", - "id": "448356f1-141a-43aa-85c0-8399eb86dd92", + "id": "197", "metadata": {}, "source": [ "As you can see, each closure maintains a reference to the `initial_value` variable that was created when the `counter()` function was **called**.\n", @@ -2179,7 +2179,7 @@ }, { "cell_type": "markdown", - "id": "b44f078d-99a5-4182-bf5c-8534874b13fd", + "id": "198", "metadata": {}, "source": [ "Let's extend this example to a **function counter**: a counter that keeps track how many times a function is run." @@ -2188,7 +2188,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b70ff4ba-fe36-4a8a-8722-9983f7836e65", + "id": "199", "metadata": {}, "outputs": [], "source": [ @@ -2206,7 +2206,7 @@ }, { "cell_type": "markdown", - "id": "9106d52f-4d4d-44ac-8b14-2d01aa530764", + "id": "200", "metadata": {}, "source": [ "Let's define a function we want to keep track of:" @@ -2215,7 +2215,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4ed85089-96f6-43bf-a339-c0b4a61652aa", + "id": "201", "metadata": {}, "outputs": [], "source": [ @@ -2228,7 +2228,7 @@ { "cell_type": "code", "execution_count": null, - "id": "02a87923-d871-4689-b486-97d832daa504", + "id": "202", "metadata": {}, "outputs": [], "source": [ @@ -2237,7 +2237,7 @@ }, { "cell_type": "markdown", - "id": "b1400efa-d0d4-4fe9-8d97-81bd012c9c0d", + "id": "203", "metadata": {}, "source": [ "We have **two** free variables, one of which is a function (remember: functions are objects)." @@ -2246,7 +2246,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55821ef1-6d90-4c5d-ab5a-35920bb169e6", + "id": "204", "metadata": {}, "outputs": [], "source": [ @@ -2256,7 +2256,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4645c14e-1024-4d6a-8fc4-a0643dfd826e", + "id": "205", "metadata": {}, "outputs": [], "source": [ @@ -2265,7 +2265,7 @@ }, { "cell_type": "markdown", - "id": "03c3e2d6-c94e-43f4-9b10-c4aff030bedf", + "id": "206", "metadata": {}, "source": [ "## Decorators" @@ -2273,7 +2273,7 @@ }, { "cell_type": "markdown", - "id": "46a4a41b-107e-4244-9b1f-75a7fde3b309", + "id": "207", "metadata": {}, "source": [ "Now that we know what closures are and what we can do with them, understanding what is a decorator is a (small) step away.\n", @@ -2284,7 +2284,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2379a0f9-d93b-4a69-9d72-9b504fda9115", + "id": "208", "metadata": {}, "outputs": [], "source": [ @@ -2302,7 +2302,7 @@ }, { "cell_type": "markdown", - "id": "c2af34e6-fb63-41ea-8885-8f1b4f9042ef", + "id": "209", "metadata": {}, "source": [ "And then create a function we want to keep track:" @@ -2311,7 +2311,7 @@ { "cell_type": "code", "execution_count": null, - "id": "937b6b94-b093-4955-98f4-2aad9caf2a16", + "id": "210", "metadata": {}, "outputs": [], "source": [ @@ -2327,7 +2327,7 @@ { "cell_type": "code", "execution_count": null, - "id": "445d8327-a1f2-41b7-86ed-860fcf1dc2b0", + "id": "211", "metadata": {}, "outputs": [], "source": [ @@ -2337,7 +2337,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c74867df-f407-4f22-8631-42fef69f09ba", + "id": "212", "metadata": {}, "outputs": [], "source": [ @@ -2347,7 +2347,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a14265c3-579e-4968-a9b9-e96dc9fc9bf2", + "id": "213", "metadata": {}, "outputs": [], "source": [ @@ -2356,7 +2356,7 @@ }, { "cell_type": "markdown", - "id": "0733182d-bd6d-4268-ad92-6647baf97ebd", + "id": "214", "metadata": {}, "source": [ "Of course, `counter_fact` is an arbitrary name.\n", @@ -2366,7 +2366,7 @@ { "cell_type": "code", "execution_count": null, - "id": "eb942a01-86d2-4d56-87d8-2008253245a8", + "id": "215", "metadata": {}, "outputs": [], "source": [ @@ -2376,7 +2376,7 @@ { "cell_type": "code", "execution_count": null, - "id": "db807859-9005-40bc-bf4a-7e00c632123b", + "id": "216", "metadata": {}, "outputs": [], "source": [ @@ -2385,7 +2385,7 @@ }, { "cell_type": "markdown", - "id": "87f34a69-b2dd-4a11-a491-227d8b73ff45", + "id": "217", "metadata": {}, "source": [ "This way of defining a function, creating a closure that \"wraps\" a function object, and then **renaming** the initial function is so common in Python that gained a special syntax:" @@ -2394,7 +2394,7 @@ { "cell_type": "code", "execution_count": null, - "id": "242d5a97-935c-4215-a9eb-9ec2d6e0f989", + "id": "218", "metadata": {}, "outputs": [], "source": [ @@ -2407,7 +2407,7 @@ { "cell_type": "code", "execution_count": null, - "id": "67da9a4e-a0bf-48e3-a28b-e1dde0bca8e3", + "id": "219", "metadata": {}, "outputs": [], "source": [ @@ -2416,7 +2416,7 @@ }, { "cell_type": "markdown", - "id": "f28db141-183b-434f-9e0a-b1eab1d90522", + "id": "220", "metadata": {}, "source": [ "The function `fcounter` is called a **decorator**, because it's placed **before** the function definition line with the special symbol `@`." @@ -2424,7 +2424,7 @@ }, { "cell_type": "markdown", - "id": "cd26059a-0e81-4c32-9324-cc08b32c7c5c", + "id": "221", "metadata": {}, "source": [ "There's one problem, though.\n", @@ -2434,7 +2434,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ce41b7be-c854-4d51-8539-635de67d1102", + "id": "222", "metadata": {}, "outputs": [], "source": [ @@ -2444,7 +2444,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ecf4afb7-f02b-4793-95bf-7aa3d78cd07f", + "id": "223", "metadata": {}, "outputs": [], "source": [ @@ -2453,7 +2453,7 @@ }, { "cell_type": "markdown", - "id": "7ce8eaef-9c35-4c4b-82ea-a54503a1f8e9", + "id": "224", "metadata": {}, "source": [ "As you can see, we've also lost our docstring and type hints!\n", @@ -2463,7 +2463,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7c4816c2-c705-41a5-911f-d8f36e9543e6", + "id": "225", "metadata": {}, "outputs": [], "source": [ @@ -2475,7 +2475,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fe8a5163-b1e4-4817-8c16-25e2a67c0120", + "id": "226", "metadata": {}, "outputs": [], "source": [ @@ -2484,7 +2484,7 @@ }, { "cell_type": "markdown", - "id": "eea17387-3cac-4982-9e39-fae19b6e6bed", + "id": "227", "metadata": {}, "source": [ "We _could_ put back that information, but it might not be straighforward:" @@ -2493,7 +2493,7 @@ { "cell_type": "code", "execution_count": null, - "id": "153128bf-aa89-4b02-9205-213fc3deeab8", + "id": "228", "metadata": {}, "outputs": [], "source": [ @@ -2515,7 +2515,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77e21a34-e89c-4419-b70c-144b803070f9", + "id": "229", "metadata": {}, "outputs": [], "source": [ @@ -2528,7 +2528,7 @@ { "cell_type": "code", "execution_count": null, - "id": "04284d5f-58d8-4821-9cb4-58da6bf1e8fa", + "id": "230", "metadata": {}, "outputs": [], "source": [ @@ -2538,7 +2538,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6de233cd-21ba-4c1e-a1a7-341a8a75f6e7", + "id": "231", "metadata": {}, "outputs": [], "source": [ @@ -2547,7 +2547,7 @@ }, { "cell_type": "markdown", - "id": "567e660a-5adb-4b8a-8e39-eba77358f77f", + "id": "232", "metadata": {}, "source": [ "Okay, at least our docstring and function's name are back.\n", @@ -2557,7 +2557,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0864b0f5-4a50-4444-aa5e-942e8c04d29e", + "id": "233", "metadata": {}, "outputs": [], "source": [ @@ -2566,7 +2566,7 @@ }, { "cell_type": "markdown", - "id": "d71b09d2-fe46-485c-a73d-594ab13da6b8", + "id": "234", "metadata": {}, "source": [ "Unfortunately, they stil belong to the `inner` function.\n", @@ -2578,7 +2578,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57485151-33e2-4b29-a449-0e379975efe1", + "id": "235", "metadata": {}, "outputs": [], "source": [ @@ -2600,7 +2600,7 @@ { "cell_type": "code", "execution_count": null, - "id": "87968847-225f-45fb-8d07-37cc7a52cef0", + "id": "236", "metadata": {}, "outputs": [], "source": [ @@ -2613,7 +2613,7 @@ { "cell_type": "code", "execution_count": null, - "id": "02d33237-63ca-4c50-ac37-21cda9dc262a", + "id": "237", "metadata": {}, "outputs": [], "source": [ @@ -2623,7 +2623,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a73c3ea7-7755-434c-8a70-b0c7b3eebc6b", + "id": "238", "metadata": {}, "outputs": [], "source": [ @@ -2633,7 +2633,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4fbb7916-ed84-42cb-9869-e117eff96b7c", + "id": "239", "metadata": {}, "outputs": [], "source": [ @@ -2642,7 +2642,7 @@ }, { "cell_type": "markdown", - "id": "d1187b91-b02a-4f92-8c15-5d6618225140", + "id": "240", "metadata": {}, "source": [ "And now everything is back to normal." @@ -2650,7 +2650,7 @@ }, { "cell_type": "markdown", - "id": "ae092a72-f0e7-4f32-89c3-5ff12d1c27a5", + "id": "241", "metadata": {}, "source": [ "### Decorators: examples" @@ -2658,7 +2658,7 @@ }, { "cell_type": "markdown", - "id": "851353f7-fa38-49ef-b265-1950ff0d0715", + "id": "242", "metadata": {}, "source": [ "#### Example 1: timer" @@ -2666,7 +2666,7 @@ }, { "cell_type": "markdown", - "id": "f2951d11-964f-4b3d-a631-fe853e458739", + "id": "243", "metadata": {}, "source": [ "This is classic example of using decorators: creating a timer for a generic function." @@ -2675,7 +2675,7 @@ { "cell_type": "code", "execution_count": null, - "id": "efc370cb-7f4f-4e5e-bbd4-f20c0760eb81", + "id": "244", "metadata": {}, "outputs": [], "source": [ @@ -2707,7 +2707,7 @@ }, { "cell_type": "markdown", - "id": "2d9bf042-cc6f-4adb-a901-54bf0d8f92ce", + "id": "245", "metadata": {}, "source": [ "Let's test it with a function to calculate the n-th Fibonacci number: `1, 1, 2, 3, 5, 8, 11, ...`\n", @@ -2723,7 +2723,7 @@ }, { "cell_type": "markdown", - "id": "cac78813-e4cf-4156-9ce1-2f725f3a0272", + "id": "246", "metadata": {}, "source": [ "##### Fibonacci with recursion" @@ -2732,7 +2732,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a24b09c5-97ce-42b5-9a05-ffe0265c0a23", + "id": "247", "metadata": {}, "outputs": [], "source": [ @@ -2745,7 +2745,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4a161836-1271-460d-822d-ec9d58482606", + "id": "248", "metadata": {}, "outputs": [], "source": [ @@ -2755,7 +2755,7 @@ { "cell_type": "code", "execution_count": null, - "id": "68504937-8af3-414e-a702-b6686e0694b7", + "id": "249", "metadata": {}, "outputs": [], "source": [ @@ -2765,7 +2765,7 @@ { "cell_type": "code", "execution_count": null, - "id": "614a913c-59ca-4a0d-bfd9-ab764ea9eace", + "id": "250", "metadata": {}, "outputs": [], "source": [ @@ -2777,7 +2777,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4ef9b981-58e2-455a-a037-784790ba7efa", + "id": "251", "metadata": {}, "outputs": [], "source": [ @@ -2787,7 +2787,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42c695d9-1659-4154-aabf-7a177eb40ebe", + "id": "252", "metadata": {}, "outputs": [], "source": [ @@ -2797,7 +2797,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d3da9690-6d8b-4559-af89-9dffb048bad0", + "id": "253", "metadata": {}, "outputs": [], "source": [ @@ -2806,7 +2806,7 @@ }, { "cell_type": "markdown", - "id": "30b1d00c-b868-430f-b37e-84042003d051", + "id": "254", "metadata": {}, "source": [ "Sounds a bit long, doesn't it?\n", @@ -2816,7 +2816,7 @@ }, { "cell_type": "markdown", - "id": "56480f96-ebd2-41ff-8ab9-e6d361fbab6c", + "id": "255", "metadata": {}, "source": [ "##### Fibonacci with a simple loop" @@ -2825,7 +2825,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0fb9d93b-458c-4ba5-841a-a1c635c7edab", + "id": "256", "metadata": {}, "outputs": [], "source": [ @@ -2843,7 +2843,7 @@ { "cell_type": "code", "execution_count": null, - "id": "80491592-1e14-418d-ad07-763309d433a3", + "id": "257", "metadata": {}, "outputs": [], "source": [ @@ -2853,7 +2853,7 @@ }, { "cell_type": "markdown", - "id": "963ec600-406d-491c-a39e-46d7d5862c8b", + "id": "258", "metadata": {}, "source": [ "Incredibly more efficient!\n", @@ -2862,7 +2862,7 @@ }, { "cell_type": "markdown", - "id": "40658db4-2751-4778-a801-3b87eec988b5", + "id": "259", "metadata": {}, "source": [ "##### Fibonacci using `reduce`" @@ -2870,7 +2870,7 @@ }, { "cell_type": "markdown", - "id": "ca74bba8-b255-4460-b957-5f9990048b3f", + "id": "260", "metadata": {}, "source": [ "First, a quick refresher:" @@ -2879,7 +2879,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3914bc14-5216-4bde-a1f7-2d5672c36885", + "id": "261", "metadata": {}, "outputs": [], "source": [ @@ -2889,7 +2889,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9b5209ea-958b-47c3-8b9f-a6f7496ffad7", + "id": "262", "metadata": {}, "outputs": [], "source": [ @@ -2898,7 +2898,7 @@ }, { "cell_type": "markdown", - "id": "2b308e95-0eb7-4096-bc77-0bad55e3895c", + "id": "263", "metadata": {}, "source": [ "It's just the progressive sum of pairs of numbers.\n", @@ -2907,7 +2907,7 @@ }, { "cell_type": "markdown", - "id": "9cd0be33-3259-4459-b25c-c077e2aa5d87", + "id": "264", "metadata": {}, "source": [ "To calculate the Fibonacci sequence with `reduce`:\n", @@ -2940,7 +2940,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76da0450-1c18-465a-916b-a7a14e4d6c51", + "id": "265", "metadata": {}, "outputs": [], "source": [ @@ -2954,7 +2954,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bac97e9b-b2d3-4a7c-9dc2-2afd10c056a9", + "id": "266", "metadata": {}, "outputs": [], "source": [ @@ -2964,7 +2964,7 @@ }, { "cell_type": "markdown", - "id": "f6908625-d87b-4290-a26b-f7584d02fbb3", + "id": "267", "metadata": {}, "source": [ "If we compare the three methods:" @@ -2973,7 +2973,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1380b3c9-5848-4c20-ba24-a31821d55467", + "id": "268", "metadata": {}, "outputs": [], "source": [ @@ -2984,7 +2984,7 @@ }, { "cell_type": "markdown", - "id": "d538441b-7e05-4f09-81ee-b9c07f457cfe", + "id": "269", "metadata": {}, "source": [ "Although the recursive method is the __easiest__ to understand, it's also the slowest because it's written inefficiently.\n", @@ -2993,7 +2993,7 @@ }, { "cell_type": "markdown", - "id": "cd0bdfaf-8869-42da-bbda-b2e7c58cac1b", + "id": "270", "metadata": {}, "source": [ "#### Example 2: memoization" @@ -3001,7 +3001,7 @@ }, { "cell_type": "markdown", - "id": "a6855d4c-4bee-499c-a83b-4a757f9bacd2", + "id": "271", "metadata": {}, "source": [ "The previous example showed one task that a decorator can accomplish pretty well: adding some feature to a predefined function.\n", @@ -3010,7 +3010,7 @@ }, { "cell_type": "markdown", - "id": "29a3838a-b172-4b22-accd-2f28631f9015", + "id": "272", "metadata": {}, "source": [ "Remember the Fibonacci sequence example.\n", @@ -3020,7 +3020,7 @@ { "cell_type": "code", "execution_count": null, - "id": "037ea535-54b8-46a3-a792-73d178bf9156", + "id": "273", "metadata": {}, "outputs": [], "source": [ @@ -3032,7 +3032,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3a21a00e-25e3-407d-9a3c-ad635fa4c711", + "id": "274", "metadata": {}, "outputs": [], "source": [ @@ -3041,7 +3041,7 @@ }, { "cell_type": "markdown", - "id": "70b34b5f-329a-4ed7-893f-bd5c941e7717", + "id": "275", "metadata": {}, "source": [ "You can see that `fib(2)` is calculated **three times**.\n", @@ -3051,7 +3051,7 @@ }, { "cell_type": "markdown", - "id": "3d051bd9-356e-43ae-9241-01ca0685f806", + "id": "276", "metadata": {}, "source": [ "We'll see how we can improve this approach using a decorator and a caching mechanism for previously calculated numbers.\n", @@ -3060,7 +3060,7 @@ }, { "cell_type": "markdown", - "id": "d0dc6010-55bf-4f05-ad43-0d23e37e0adb", + "id": "277", "metadata": {}, "source": [ "For the sake of comparison, let's first approach this problem with a simple class:" @@ -3069,7 +3069,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74bcdcf3-fd56-407b-a29e-2e389a9b7119", + "id": "278", "metadata": {}, "outputs": [], "source": [ @@ -3087,7 +3087,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a4410484-9f84-4129-bbb7-03aa54b86ebd", + "id": "279", "metadata": {}, "outputs": [], "source": [ @@ -3098,7 +3098,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e1c4e895-0df0-44f5-a433-2e301aa6a42a", + "id": "280", "metadata": {}, "outputs": [], "source": [ @@ -3107,7 +3107,7 @@ }, { "cell_type": "markdown", - "id": "5eb4de0f-8764-4780-902d-866ed71c083d", + "id": "281", "metadata": {}, "source": [ "You can see that numbers $\\leq 10$ are **not** recalculated, but are fetched from the cache.\n", @@ -3118,7 +3118,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d3c8d45b-8206-430e-b036-ace879fb5eeb", + "id": "282", "metadata": {}, "outputs": [], "source": [ @@ -3138,7 +3138,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e70c5950-aebc-46ce-adb9-7aef09842f49", + "id": "283", "metadata": {}, "outputs": [], "source": [ @@ -3149,7 +3149,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d4b745b4-3949-4311-af3f-59ea310a8693", + "id": "284", "metadata": {}, "outputs": [], "source": [ @@ -3158,7 +3158,7 @@ }, { "cell_type": "markdown", - "id": "70606145-7e3d-4d39-b912-0a9417243c2b", + "id": "285", "metadata": {}, "source": [ "Once again, cached valued are just returned and not recalculated." @@ -3166,7 +3166,7 @@ }, { "cell_type": "markdown", - "id": "d5909ef9-5a98-4b10-b75b-7e2524f7476a", + "id": "286", "metadata": {}, "source": [ "How can we implement this as a decorator?" @@ -3175,7 +3175,7 @@ { "cell_type": "code", "execution_count": null, - "id": "927c6b8c-53b0-429e-9056-a73ce32c1118", + "id": "287", "metadata": {}, "outputs": [], "source": [ @@ -3196,7 +3196,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5e31857a-01f4-462a-b1b5-589991580de0", + "id": "288", "metadata": {}, "outputs": [], "source": [ @@ -3209,7 +3209,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3bbe4852-3229-48d3-9b57-aa8bd5fb19c8", + "id": "289", "metadata": {}, "outputs": [], "source": [ @@ -3219,7 +3219,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ecd39ea1-6452-4d08-ba34-0ef25c2cb8c8", + "id": "290", "metadata": {}, "outputs": [], "source": [ @@ -3229,7 +3229,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6a3349e4-fbf4-46ec-ad3f-8f024338eda0", + "id": "291", "metadata": {}, "outputs": [], "source": [ @@ -3238,7 +3238,7 @@ }, { "cell_type": "markdown", - "id": "0601bada-12d1-4ea5-88a3-dea98a518da2", + "id": "292", "metadata": {}, "source": [ "`fib(6)` was literally instantaneous because we already had it in the cache." @@ -3246,7 +3246,7 @@ }, { "cell_type": "markdown", - "id": "9e4d6bd0-be10-4e9c-82fd-e858217c28ba", + "id": "293", "metadata": {}, "source": [ "How to create a generic decorator that caches the return values of **any** function?\n", @@ -3256,7 +3256,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0dcc0d34-4ce6-4226-93ad-60cdbffb82e8", + "id": "294", "metadata": {}, "outputs": [], "source": [ @@ -3274,7 +3274,7 @@ }, { "cell_type": "markdown", - "id": "bda787dc-56c4-4039-9dfb-0bde5a2ecb74", + "id": "295", "metadata": {}, "source": [ "And we can now give any function a cache to store previously calculated results:" @@ -3283,7 +3283,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3305b178-4529-490b-b874-f90e2e04057b", + "id": "296", "metadata": {}, "outputs": [], "source": [ @@ -3296,7 +3296,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cdb57a21-3369-429b-be6b-d8070f6274d8", + "id": "297", "metadata": {}, "outputs": [], "source": [ @@ -3306,7 +3306,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85424c51-aad7-4a65-86be-dfcae38fca5d", + "id": "298", "metadata": {}, "outputs": [], "source": [ @@ -3316,7 +3316,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9e72cc94-1625-4a31-bfc5-9c5d960ebf9c", + "id": "299", "metadata": {}, "outputs": [], "source": [ @@ -3325,7 +3325,7 @@ }, { "cell_type": "markdown", - "id": "97663e19-c050-4ddd-9966-5517329f82d1", + "id": "300", "metadata": {}, "source": [ "Caching and decorators play a crucial role in optimizing function performance.\n", @@ -3338,7 +3338,7 @@ }, { "cell_type": "markdown", - "id": "34a56f44-3a4a-4ef5-b13d-a8996c2705cb", + "id": "301", "metadata": {}, "source": [ "Additionally, our current implementation does not handle keyword arguments (`**kwargs`), which can be a significant limitation in more complex scenarios.\n", @@ -3352,7 +3352,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85542bcc-f74a-4ad1-8f49-0f28a05924a1", + "id": "302", "metadata": {}, "outputs": [], "source": [ @@ -3362,7 +3362,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e3dc8989-b32f-4df1-abfe-163b8e402a3d", + "id": "303", "metadata": {}, "outputs": [], "source": [ @@ -3375,7 +3375,7 @@ { "cell_type": "code", "execution_count": null, - "id": "58e99db4-c68f-4361-b1fc-4a36d56bc63c", + "id": "304", "metadata": {}, "outputs": [], "source": [ @@ -3385,7 +3385,7 @@ }, { "cell_type": "markdown", - "id": "f2ff8c04-31b2-41cf-9d53-5f342770a4ab", + "id": "305", "metadata": {}, "source": [ "Once again, the last value `fact(8)` was simply fetched from the cache." @@ -3393,7 +3393,7 @@ }, { "cell_type": "markdown", - "id": "0127faae-a296-41d2-b369-19e0af6e87dd", + "id": "306", "metadata": {}, "source": [ "Now let's see if we have improved on our recursive approach of calculating Fibonacci numbers.\n", @@ -3403,7 +3403,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bbe7626d-d436-41e0-85f0-803ee8033399", + "id": "307", "metadata": {}, "outputs": [], "source": [ @@ -3413,7 +3413,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3ca9a287-aff9-493a-9904-9f583ee2d32e", + "id": "308", "metadata": {}, "outputs": [], "source": [ @@ -3424,7 +3424,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3f23099d-5362-4629-ad10-816a61318118", + "id": "309", "metadata": {}, "outputs": [], "source": [ @@ -3438,7 +3438,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53f342fd-8e57-4960-8fb4-65a9164d1b4f", + "id": "310", "metadata": {}, "outputs": [], "source": [ @@ -3450,7 +3450,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6205cc9e-47f0-46c1-ad92-f066dd5f2e29", + "id": "311", "metadata": {}, "outputs": [], "source": [ @@ -3463,7 +3463,7 @@ }, { "cell_type": "markdown", - "id": "db34d63c-f25e-4d4f-aa7e-19aea575a6cb", + "id": "312", "metadata": {}, "source": [ "It's about **4 orders of magnitude** faster than the naive approach! 🔥\n", @@ -3473,7 +3473,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71c5f5ed-c8cf-493b-a8ae-4af3cfcac730", + "id": "313", "metadata": {}, "outputs": [], "source": [ @@ -3487,7 +3487,7 @@ { "cell_type": "code", "execution_count": null, - "id": "344492e4-35cd-4f1e-953c-6a25ed824beb", + "id": "314", "metadata": {}, "outputs": [], "source": [ @@ -3500,7 +3500,7 @@ }, { "cell_type": "markdown", - "id": "e4b2b121-1fa2-41c2-bc4c-6cfc8fa018de", + "id": "315", "metadata": {}, "source": [ "Not the same time, but about the same order of magnitude.\n", @@ -3509,7 +3509,7 @@ }, { "cell_type": "markdown", - "id": "b2ed8eac-d3be-4de5-894a-f72efc2c2046", + "id": "316", "metadata": {}, "source": [ "You may have noticed that `lru_cache` was called an **empty list of arguments**, but it supports some.\n", @@ -3520,7 +3520,7 @@ { "cell_type": "code", "execution_count": null, - "id": "af2d1111-b1e8-41d9-94cf-5a385d143ba4", + "id": "317", "metadata": {}, "outputs": [], "source": [ @@ -3533,7 +3533,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4d7667da-ef73-44e1-a502-4e7bee54db8b", + "id": "318", "metadata": {}, "outputs": [], "source": [ @@ -3543,7 +3543,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33242e6d-3695-43bb-8e3f-22b3a5455d7a", + "id": "319", "metadata": {}, "outputs": [], "source": [ @@ -3553,7 +3553,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4558e886-905b-4a75-86ca-5b52d113baca", + "id": "320", "metadata": {}, "outputs": [], "source": [ @@ -3562,7 +3562,7 @@ }, { "cell_type": "markdown", - "id": "defa65f2-8f62-45c5-a295-78eca6320b14", + "id": "321", "metadata": {}, "source": [ "We had to recalculate `fib(1)` because when we called `fib(9)` the least recent item in the cache (the result of `fib(1)`) was evicted from the cache." @@ -3570,7 +3570,7 @@ }, { "cell_type": "markdown", - "id": "11cfa5cb-e95f-47fd-8eda-de7b671e4a0c", + "id": "322", "metadata": {}, "source": [ "### Parametrized decorators" @@ -3578,7 +3578,7 @@ }, { "cell_type": "markdown", - "id": "56dec685-4796-483a-b4f6-86652160af57", + "id": "323", "metadata": {}, "source": [ "Here comes a natural question: what if I need to pass some argument to my decorator?\n", @@ -3587,7 +3587,7 @@ }, { "cell_type": "markdown", - "id": "5e80180f-c6ec-4298-a276-75b84e35aa8e", + "id": "324", "metadata": {}, "source": [ "Let's bring back our `timed` decorator and make a small change.\n", @@ -3597,7 +3597,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c4f17d45-364d-4af7-9c8d-2be2c34c6eed", + "id": "325", "metadata": {}, "outputs": [], "source": [ @@ -3625,7 +3625,7 @@ { "cell_type": "code", "execution_count": null, - "id": "07889c31-4a4a-45f2-a6a4-e0da8cdf19bf", + "id": "326", "metadata": {}, "outputs": [], "source": [ @@ -3640,7 +3640,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7664bbd0-beec-42b8-88fa-a634781e40c7", + "id": "327", "metadata": {}, "outputs": [], "source": [ @@ -3649,7 +3649,7 @@ }, { "cell_type": "markdown", - "id": "7fcf76cf-906c-4d8b-a69d-163ec31fa4d9", + "id": "328", "metadata": {}, "source": [ "But what if I wanted to time this function **100 times**?\n", @@ -3662,7 +3662,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8649f150-aeaa-4d6e-a8e1-e8e6f444e4af", + "id": "329", "metadata": {}, "outputs": [], "source": [ @@ -3687,7 +3687,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6033e377-bb3c-458f-8df9-c29fe6ec0ade", + "id": "330", "metadata": {}, "outputs": [], "source": [ @@ -3700,7 +3700,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f52d07c1-53a5-4f70-beee-b4ea23dec26b", + "id": "331", "metadata": {}, "outputs": [], "source": [ @@ -3709,7 +3709,7 @@ }, { "cell_type": "markdown", - "id": "8949b05a-b68f-4c6d-9cd5-f44eb394a973", + "id": "332", "metadata": {}, "source": [ "But wait: why did we use the fancy `@-` syntax?\n", @@ -3718,7 +3718,7 @@ }, { "cell_type": "markdown", - "id": "b6badfec-b32c-416c-9c51-4291666b2ed8", + "id": "333", "metadata": {}, "source": [ "To fix this behavior we need to rethink of what `@` is doing.\n", @@ -3742,7 +3742,7 @@ { "cell_type": "code", "execution_count": null, - "id": "604bd997-d375-4620-a3f8-84daa3ba63f1", + "id": "334", "metadata": {}, "outputs": [], "source": [ @@ -3752,7 +3752,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42189578-2918-4525-9e40-184d8b527434", + "id": "335", "metadata": {}, "outputs": [], "source": [ @@ -3761,7 +3761,7 @@ }, { "cell_type": "markdown", - "id": "7f702383-31b4-42a9-b97b-d6ef5d34d6cc", + "id": "336", "metadata": {}, "source": [ "So, for the syntax `@timed(10)` to work, where `10` is the number of repetition, `timed` should return **a decorator itself**, and not our closure.\n", @@ -3771,7 +3771,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6975521b-162d-495f-b185-b86559cddd86", + "id": "337", "metadata": {}, "outputs": [], "source": [ @@ -3805,7 +3805,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f097a33c-48b7-4ee3-9460-53b31a5835c1", + "id": "338", "metadata": {}, "outputs": [], "source": [ @@ -3820,7 +3820,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f87ec0fe-ef8d-4d5a-b8cf-56eb24cce6e8", + "id": "339", "metadata": {}, "outputs": [], "source": [ @@ -3830,7 +3830,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85f7bc42-d42e-41ca-8bc4-b2a1369b765e", + "id": "340", "metadata": {}, "outputs": [], "source": [ @@ -3848,7 +3848,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6d205959-7384-4a5a-a5fd-a60816ae102b", + "id": "341", "metadata": {}, "outputs": [], "source": [ @@ -3857,7 +3857,7 @@ }, { "cell_type": "markdown", - "id": "a17be0fa-db15-4a09-b92e-4da09c5d3c3a", + "id": "342", "metadata": {}, "source": [ "And yes, you can **stack multiple decorators**! 😎" @@ -3865,7 +3865,7 @@ }, { "cell_type": "markdown", - "id": "4d73ede6-b0ef-435f-9eb5-ef10a4f099e0", + "id": "343", "metadata": {}, "source": [ "## Generators" @@ -3873,7 +3873,7 @@ }, { "cell_type": "markdown", - "id": "93753115-b428-49ad-883b-29d1ad5cefef", + "id": "344", "metadata": {}, "source": [ "The concept of generators is very much tied to that of \"looping over some kind of container\".\n", @@ -3890,7 +3890,7 @@ }, { "cell_type": "markdown", - "id": "210bcc5e-58cf-466d-8e17-2f0c4c9eaec1", + "id": "345", "metadata": {}, "source": [ "To understand generators, we first need to review what it means to be **iterable** and, more importantly, what is an **iterator**.\n", @@ -3901,7 +3901,7 @@ }, { "cell_type": "markdown", - "id": "015bb6cd-f87b-4b8b-acd6-5087bca63911", + "id": "346", "metadata": {}, "source": [ "Delving deep into iterators is out of the scope of this section, so we are going to show you a practical example of a class that implements the \"iterator protocol\".\n", @@ -3912,7 +3912,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a5202c22-1018-4652-a75d-b5027f6de5fd", + "id": "347", "metadata": {}, "outputs": [], "source": [ @@ -3935,7 +3935,7 @@ { "cell_type": "code", "execution_count": null, - "id": "192ba5cc-bd97-4310-9ad4-ff520ea8050f", + "id": "348", "metadata": {}, "outputs": [], "source": [ @@ -3945,7 +3945,7 @@ }, { "cell_type": "markdown", - "id": "aa22aa62-570b-43c1-bbf4-6948ed8940cb", + "id": "349", "metadata": {}, "source": [ "We see that we can indeed loop over our custom `Squares` class.\n", @@ -3958,7 +3958,7 @@ }, { "cell_type": "markdown", - "id": "89b69921-b35b-4c6b-a958-a11697e37ec8", + "id": "350", "metadata": {}, "source": [ "As you might have learned by now, we can implement some built-in behavior in our classes by using the so-called \"special methods\" or **dunder methods**: those with this naming schema `__method__`.\n", @@ -3972,7 +3972,7 @@ }, { "cell_type": "markdown", - "id": "cf30162e-8c18-4dbe-be1e-f0796d1ceecf", + "id": "351", "metadata": {}, "source": [ "Python also has the built-in `next()` which does what you think it does: it takes an **iterator** object and returns the next element in the stream of data by calling the `__next__` method implemented by that object.\n", @@ -3985,7 +3985,7 @@ }, { "cell_type": "markdown", - "id": "a41a06b7-b900-457e-bbe5-2e1f49d03260", + "id": "352", "metadata": {}, "source": [ "We could've written our `Squares` class using a closure instead:" @@ -3994,7 +3994,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32ed78a0-093c-4c0f-ad1e-08040f0767f2", + "id": "353", "metadata": {}, "outputs": [], "source": [ @@ -4012,7 +4012,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cf6b292a-0b8b-483a-b6c2-02197ed0a617", + "id": "354", "metadata": {}, "outputs": [], "source": [ @@ -4022,7 +4022,7 @@ }, { "cell_type": "markdown", - "id": "2c7e0730-2f0b-4c05-b327-0c608f1d8e6e", + "id": "355", "metadata": {}, "source": [ "If the value returned by `square()` is 25 (our sentinel), then a `StopIteration` is raised." @@ -4030,7 +4030,7 @@ }, { "cell_type": "markdown", - "id": "60418aad-f45f-4e8d-92f8-f1d25c31a3ac", + "id": "356", "metadata": {}, "source": [ "These two ways are identical: in the first case (the class), we built the iterator ourselves. In the second case, Python built it for us.\n", @@ -4041,7 +4041,7 @@ }, { "cell_type": "markdown", - "id": "12189bba-06b8-46d7-ade8-d98f155ccec4", + "id": "357", "metadata": {}, "source": [ "The `yield` statement is used almost like a `return` statement in a function, but there is a huge difference.\n", @@ -4054,7 +4054,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bcebcd57-1eb3-464b-90a1-a4472460ee9f", + "id": "358", "metadata": {}, "outputs": [], "source": [ @@ -4070,7 +4070,7 @@ { "cell_type": "code", "execution_count": null, - "id": "02645231-a433-4d6d-b715-44ad0c8de2c5", + "id": "359", "metadata": {}, "outputs": [], "source": [ @@ -4080,7 +4080,7 @@ }, { "cell_type": "markdown", - "id": "a64b6ee5-c532-4562-bf28-de0d49ce5214", + "id": "360", "metadata": {}, "source": [ "Here it is: our function returned _something_ different than the usual \"function\" object.\n", @@ -4090,7 +4090,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d481c9c0-da8a-4b32-a6d4-2ad26a32a1dd", + "id": "361", "metadata": {}, "outputs": [], "source": [ @@ -4100,7 +4100,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5b73e97f-af8a-4aeb-8e09-8c78fd90ad0e", + "id": "362", "metadata": {}, "outputs": [], "source": [ @@ -4110,7 +4110,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7f4792ae-2e76-496e-83d6-e5fa0cd3b511", + "id": "363", "metadata": {}, "outputs": [], "source": [ @@ -4120,7 +4120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "08af1d98-6ef1-4b91-9cb8-36e84a89c803", + "id": "364", "metadata": {}, "outputs": [], "source": [ @@ -4129,7 +4129,7 @@ }, { "cell_type": "markdown", - "id": "fd0cd226-51e9-4776-b02d-805900edce5e", + "id": "365", "metadata": {}, "source": [ "A `StopIteration` is raised if we are trying to go past the last `yield` statement.\n", @@ -4142,7 +4142,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4d97ad51-16ea-48c6-bcab-fbf7dd09e1cc", + "id": "366", "metadata": {}, "outputs": [], "source": [ @@ -4151,7 +4151,7 @@ }, { "cell_type": "markdown", - "id": "f14e9fd4-ab5b-44fa-bf3c-c65f2f931ab4", + "id": "367", "metadata": {}, "source": [ "And also the `__next__` method" @@ -4160,7 +4160,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c0c60262-cf6b-445d-8026-5da9623f2cae", + "id": "368", "metadata": {}, "outputs": [], "source": [ @@ -4169,7 +4169,7 @@ }, { "cell_type": "markdown", - "id": "f4727a96-ecab-4ed2-bccb-665bad5b5935", + "id": "369", "metadata": {}, "source": [ "We can also check that `iter()` applied on our object returns indeed the same thing.\n", @@ -4179,7 +4179,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d52671aa-ae89-4ffa-a86f-d7b8d4801d19", + "id": "370", "metadata": {}, "outputs": [], "source": [ @@ -4189,7 +4189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb89ae4b-6e03-449a-853d-783ef380a904", + "id": "371", "metadata": {}, "outputs": [], "source": [ @@ -4198,7 +4198,7 @@ }, { "cell_type": "markdown", - "id": "9e43f3ba-8b8b-49c7-a10d-44640df0ad65", + "id": "372", "metadata": {}, "source": [ "Precisely the same object." @@ -4206,7 +4206,7 @@ }, { "cell_type": "markdown", - "id": "c2a8686c-3ebe-449b-9857-0d33284c8d3a", + "id": "373", "metadata": {}, "source": [ "How Python knows when to stop the iteration?\n", @@ -4222,7 +4222,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b0d6a96c-03b2-4c5c-97b5-e8eeb92d3459", + "id": "374", "metadata": {}, "outputs": [], "source": [ @@ -4239,7 +4239,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c3036908-c8a4-4fb8-8ba4-0d4923af2bcc", + "id": "375", "metadata": {}, "outputs": [], "source": [ @@ -4250,7 +4250,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3b22bd05-6164-4d0f-b056-bc99c9cac527", + "id": "376", "metadata": {}, "outputs": [], "source": [ @@ -4260,7 +4260,7 @@ { "cell_type": "code", "execution_count": null, - "id": "135dd1b8-557b-4b40-9b91-3025f0e956db", + "id": "377", "metadata": {}, "outputs": [], "source": [ @@ -4270,7 +4270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7b0200d9-4c70-46df-ab4a-83d942aa439d", + "id": "378", "metadata": {}, "outputs": [], "source": [ @@ -4279,7 +4279,7 @@ }, { "cell_type": "markdown", - "id": "31517002-ba25-41f3-81ae-113b3ddbb8ac", + "id": "379", "metadata": {}, "source": [ "Note how in the generator function above we incremented the number `i` **after** the `yield` statement.\n", @@ -4288,7 +4288,7 @@ }, { "cell_type": "markdown", - "id": "3cbf6eab-aff5-4e39-b974-559d581d7d2a", + "id": "380", "metadata": {}, "source": [ "### Create an interable from a generator" @@ -4296,7 +4296,7 @@ }, { "cell_type": "markdown", - "id": "379ea24c-55eb-4a8b-85b8-4747c988af2d", + "id": "381", "metadata": {}, "source": [ "As we know, generators are iterators.\n", @@ -4308,7 +4308,7 @@ }, { "cell_type": "markdown", - "id": "eb5c13df-f019-4f7d-8e2d-55c2bfff6f96", + "id": "382", "metadata": {}, "source": [ "Let's consider again the example of generating squares of integers:" @@ -4317,7 +4317,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a3a39c29-fb62-4bed-957f-ea38fdad1665", + "id": "383", "metadata": {}, "outputs": [], "source": [ @@ -4329,7 +4329,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1f78d206-0dc6-4ef1-8016-6a3a9430dea7", + "id": "384", "metadata": {}, "outputs": [], "source": [ @@ -4339,7 +4339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5f82b60a-e623-4d86-98fb-7eef3bc72dca", + "id": "385", "metadata": {}, "outputs": [], "source": [ @@ -4349,7 +4349,7 @@ }, { "cell_type": "markdown", - "id": "564771fe-2f21-4d8d-97f2-b2f592623426", + "id": "386", "metadata": {}, "source": [ "But our generator is now exhausted and it has nothing left to return:" @@ -4358,7 +4358,7 @@ { "cell_type": "code", "execution_count": null, - "id": "af2a0872-99fe-440c-8767-959a3ec95338", + "id": "387", "metadata": {}, "outputs": [], "source": [ @@ -4367,7 +4367,7 @@ }, { "cell_type": "markdown", - "id": "9a14144f-e80a-4a9b-99f8-2b4eceda4217", + "id": "388", "metadata": {}, "source": [ "To restart the iteration, we need to create another instance of the generator.\n", @@ -4377,7 +4377,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33e71361-0245-4cc3-bc5d-73c11d0ab59f", + "id": "389", "metadata": {}, "outputs": [], "source": [ @@ -4392,7 +4392,7 @@ { "cell_type": "code", "execution_count": null, - "id": "305966ad-0c54-4edb-86de-2008653874fa", + "id": "390", "metadata": {}, "outputs": [], "source": [ @@ -4402,7 +4402,7 @@ }, { "cell_type": "markdown", - "id": "2e104cb5-3c8a-4d62-b3f9-50472a3a85e3", + "id": "391", "metadata": {}, "source": [ "And we can do it again:" @@ -4411,7 +4411,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76499d2b-227b-4558-8815-1325baa1379a", + "id": "392", "metadata": {}, "outputs": [], "source": [ @@ -4420,7 +4420,7 @@ }, { "cell_type": "markdown", - "id": "10db0c6c-7d58-40b5-8600-28f4876f6899", + "id": "393", "metadata": {}, "source": [ "We can put everything is a single class to make things easier to read:" @@ -4429,7 +4429,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cc5b2d58-ac9a-451a-ae31-ca212ba74843", + "id": "394", "metadata": {}, "outputs": [], "source": [ @@ -4449,7 +4449,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3ed78f78-2054-4b72-9715-17f45d8e1754", + "id": "395", "metadata": {}, "outputs": [], "source": [ @@ -4459,7 +4459,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb1c8334-1263-43d9-b626-72513e2ea779", + "id": "396", "metadata": {}, "outputs": [], "source": [ @@ -4469,7 +4469,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d281f4d9-2e91-41c7-9287-ce7bfd79def2", + "id": "397", "metadata": {}, "outputs": [], "source": [ @@ -4478,7 +4478,7 @@ }, { "cell_type": "markdown", - "id": "57990dd0-af52-4316-a71b-bd28edf57cd6", + "id": "398", "metadata": {}, "source": [ "### Combining generators" @@ -4486,7 +4486,7 @@ }, { "cell_type": "markdown", - "id": "95750a37-00ee-4292-ac6c-f64320048327", + "id": "399", "metadata": {}, "source": [ "We have to be careful when using a generator with one another.\n", @@ -4496,7 +4496,7 @@ { "cell_type": "code", "execution_count": null, - "id": "462988f1-79f4-4a3d-997e-c415c7301691", + "id": "400", "metadata": {}, "outputs": [], "source": [ @@ -4508,7 +4508,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6767cfe1-bc52-424b-8665-cfd7f4b36dd9", + "id": "401", "metadata": {}, "outputs": [], "source": [ @@ -4518,7 +4518,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b35c2c33-d798-4458-a712-75edcfbc676a", + "id": "402", "metadata": {}, "outputs": [], "source": [ @@ -4527,7 +4527,7 @@ }, { "cell_type": "markdown", - "id": "b338a634-13a3-4b93-b533-d5aa6c15e199", + "id": "403", "metadata": {}, "source": [ "Now, `enumerate` builds a generator itself, so `sq` had not been consumed yet at this point:" @@ -4536,7 +4536,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e8beb7cc-3bbb-4153-aa71-fc4def671e68", + "id": "404", "metadata": {}, "outputs": [], "source": [ @@ -4546,7 +4546,7 @@ { "cell_type": "code", "execution_count": null, - "id": "62bd58ff-2b79-4f3f-ad6f-06d22736b53c", + "id": "405", "metadata": {}, "outputs": [], "source": [ @@ -4555,7 +4555,7 @@ }, { "cell_type": "markdown", - "id": "0f2ce2d7-2ec6-428f-aa8c-94cc6d6a65b2", + "id": "406", "metadata": {}, "source": [ "But since we now have consumed **2 elements** from `sq`, when we use `enumerate` it will also have two less items from `sq`:" @@ -4564,7 +4564,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9070f983-4938-4ee1-a97a-b85ecfc2c5bd", + "id": "407", "metadata": {}, "outputs": [], "source": [ @@ -4573,7 +4573,7 @@ }, { "cell_type": "markdown", - "id": "040e46b2-206a-4051-b548-62acec5287be", + "id": "408", "metadata": {}, "source": [ "And this might not be what you expected: the value is the **third** element of `sq` ($2^2$), while the index is `0`, as if we were starting from the beginning.\n", @@ -4584,7 +4584,7 @@ }, { "cell_type": "markdown", - "id": "f5214c67-0f92-4a7f-a768-eee90dd14bbb", + "id": "409", "metadata": {}, "source": [ "## Exercises" @@ -4593,7 +4593,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69a49f30-1d16-4c84-89bc-30d6bd7421f2", + "id": "410", "metadata": {}, "outputs": [], "source": [ @@ -4602,7 +4602,7 @@ }, { "cell_type": "markdown", - "id": "777251e1-d655-4e36-a41c-ddefe020d1b7", + "id": "411", "metadata": {}, "source": [ "### Password checker factory" @@ -4610,7 +4610,7 @@ }, { "cell_type": "markdown", - "id": "bbec8f73-9b4f-49bc-bd59-c3db2ed6132d", + "id": "412", "metadata": { "jp-MarkdownHeadingCollapsed": true }, @@ -4634,7 +4634,7 @@ }, { "cell_type": "markdown", - "id": "ed1919fe-96d2-4c59-8753-9f2113aa8c3e", + "id": "413", "metadata": {}, "source": [ "For example, to create a password checker that requires a password to have at least 2 uppercase letters, at least 3 lowercase letters, at least 1 punctuation mark, and at least 4 digits, we can write\n", @@ -4664,7 +4664,7 @@ { "cell_type": "code", "execution_count": null, - "id": "565bd836-35f0-40c7-9897-653d2e6253f6", + "id": "414", "metadata": {}, "outputs": [], "source": [ @@ -4677,7 +4677,7 @@ }, { "cell_type": "markdown", - "id": "1fe377f9-0f6c-44d5-8d15-c74a8502bc52", + "id": "415", "metadata": {}, "source": [ "### String range" @@ -4685,7 +4685,7 @@ }, { "cell_type": "markdown", - "id": "740cf590-13c5-4df3-b476-7c0ca7d80e29", + "id": "416", "metadata": {}, "source": [ "Create a function called `str_range` that emulates the the built-in `range`, but for characters.\n", @@ -4699,7 +4699,7 @@ }, { "cell_type": "markdown", - "id": "48b1b02e-4971-4ee0-9d1e-7a746b847a9a", + "id": "417", "metadata": {}, "source": [ "
\n", @@ -4709,7 +4709,7 @@ }, { "cell_type": "markdown", - "id": "a0618164-199a-4211-8c83-1341c0fc84f7", + "id": "418", "metadata": {}, "source": [ "
\n", @@ -4720,7 +4720,7 @@ { "cell_type": "code", "execution_count": null, - "id": "00b721c6-87e8-4eda-8cc3-b1bca3d2bdd6", + "id": "419", "metadata": {}, "outputs": [], "source": [ @@ -4733,7 +4733,7 @@ }, { "cell_type": "markdown", - "id": "09965c4e-db8a-46a6-9b57-a4b5350ae398", + "id": "420", "metadata": {}, "source": [ "### Read `n` lines" @@ -4741,7 +4741,7 @@ }, { "cell_type": "markdown", - "id": "ba075f54-be74-41c9-9c56-a25aefb6569f", + "id": "421", "metadata": {}, "source": [ "Create a function called `read_n_lines` that takes two arguments: the filename from which to read, and the **maximum number of lines** that should be returned with each iteration.\n", @@ -4785,7 +4785,7 @@ }, { "cell_type": "markdown", - "id": "e21a3c08-1584-409f-8e3b-d36c5d22b960", + "id": "422", "metadata": {}, "source": [ "We could also do:\n", @@ -4811,7 +4811,7 @@ }, { "cell_type": "markdown", - "id": "e20056ea-b537-4cb3-9e6a-624348c8d443", + "id": "423", "metadata": {}, "source": [ "
\n", @@ -4822,7 +4822,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5d58c7d1-e361-4d41-a7d2-162ca06746b0", + "id": "424", "metadata": {}, "outputs": [], "source": [ @@ -4835,7 +4835,7 @@ }, { "cell_type": "markdown", - "id": "a941b875-c1a1-4153-9e3b-57f2ca4118b7", + "id": "425", "metadata": {}, "source": [ "### Only run once" @@ -4843,7 +4843,7 @@ }, { "cell_type": "markdown", - "id": "1867171a-da42-419e-8a13-b5727fa4f805", + "id": "426", "metadata": {}, "source": [ "Create a decorator called `once` that restricts a function to run at most **once every `allowed_time` seconds**, where `allowed_time` is a parameter with a default value of `15`.\n", @@ -4854,7 +4854,7 @@ }, { "cell_type": "markdown", - "id": "ee62b302-a6a8-4207-933f-88e2a63a634e", + "id": "427", "metadata": {}, "source": [ "For example, the following code:\n", @@ -4878,7 +4878,7 @@ }, { "cell_type": "markdown", - "id": "037e2acc-a4bd-4682-84af-861f7874ce92", + "id": "428", "metadata": {}, "source": [ "Should print something like:\n", @@ -4903,7 +4903,7 @@ }, { "cell_type": "markdown", - "id": "269e6e73-6a3b-41d7-a50e-25d20d3cf0ba", + "id": "429", "metadata": {}, "source": [ "
\n", @@ -4922,7 +4922,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23bd64fd-470c-4685-8cd2-e489a535b68c", + "id": "430", "metadata": {}, "outputs": [], "source": [ diff --git a/library_numpy.ipynb b/library_numpy.ipynb index 8fc89482..91281784 100644 --- a/library_numpy.ipynb +++ b/library_numpy.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "a0a945ae-7c8d-4b48-892a-46d0ecd4faf3", + "id": "0", "metadata": {}, "source": [ "# NumPy" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "e7e3d3be", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -64,7 +64,7 @@ }, { "cell_type": "markdown", - "id": "4cc4d35b", + "id": "2", "metadata": {}, "source": [ "# References\n", @@ -74,7 +74,7 @@ }, { "cell_type": "markdown", - "id": "1b5051a4", + "id": "3", "metadata": {}, "source": [ "# Introduction" @@ -82,7 +82,7 @@ }, { "cell_type": "markdown", - "id": "5afe42d5", + "id": "4", "metadata": {}, "source": [ "## Why NumPy?\n", @@ -104,7 +104,7 @@ }, { "cell_type": "markdown", - "id": "09dab3c6", + "id": "5", "metadata": {}, "source": [ "## What is the catch?\n", @@ -117,7 +117,7 @@ }, { "cell_type": "markdown", - "id": "b3c59e7c", + "id": "6", "metadata": {}, "source": [ "## What is NumPy?\n", @@ -140,7 +140,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c42ef463", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -157,7 +157,7 @@ }, { "cell_type": "markdown", - "id": "70b2db88", + "id": "8", "metadata": {}, "source": [ "Beaweare that unlike Python lists, the sum of two NumPy arrays is the sum of their corresponding elements, not their concatenation:" @@ -166,7 +166,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20eb40af", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -180,7 +180,7 @@ }, { "cell_type": "markdown", - "id": "9788f627", + "id": "10", "metadata": {}, "source": [ "Also, you can use mathematical functions on NumPy arrays, and they will be applied to each element of the array.\n", @@ -190,7 +190,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f408f8ad", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -203,7 +203,7 @@ }, { "cell_type": "markdown", - "id": "5b09d588", + "id": "12", "metadata": {}, "source": [ "Finally, NumPy provides a lot of functions that are useful for scientific computing.\n", @@ -213,7 +213,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32cc3c90", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -232,7 +232,7 @@ }, { "cell_type": "markdown", - "id": "3c0936c2", + "id": "14", "metadata": {}, "source": [ "Now, as got a basic idea of what NumPy is, let's dive deeper into it." @@ -240,7 +240,7 @@ }, { "cell_type": "markdown", - "id": "faf589d8", + "id": "15", "metadata": {}, "source": [ "# NumPy vocabulary\n", @@ -251,7 +251,7 @@ }, { "cell_type": "markdown", - "id": "146668e2", + "id": "16", "metadata": {}, "source": [ "# `ndarray` - the core of NumPy\n", @@ -264,7 +264,7 @@ }, { "cell_type": "markdown", - "id": "a8246904", + "id": "17", "metadata": {}, "source": [ "## Creating an `ndarray`\n", @@ -276,7 +276,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32c9a1c0", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -287,7 +287,7 @@ }, { "cell_type": "markdown", - "id": "dde7e7e6", + "id": "19", "metadata": {}, "source": [ "A common mistake is to pass to the `array()` function a bunch of numbers separated by commas, like this:\n" @@ -296,7 +296,7 @@ { "cell_type": "code", "execution_count": null, - "id": "be82d988", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -306,7 +306,7 @@ }, { "cell_type": "markdown", - "id": "d330d8ea", + "id": "21", "metadata": {}, "source": [ "The `array()` function can also take a list of lists as an argument." @@ -315,7 +315,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34e851f6", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -326,7 +326,7 @@ }, { "cell_type": "markdown", - "id": "e297a32e", + "id": "23", "metadata": {}, "source": [ "It is also OK to pass a tuple instead of a list to the `array()` function:" @@ -335,7 +335,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e35edc88", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -352,7 +352,7 @@ }, { "cell_type": "markdown", - "id": "0c061eb8", + "id": "25", "metadata": {}, "source": [ "There are several other functions that can be used to create an `ndarray`.\n", @@ -372,7 +372,7 @@ { "cell_type": "code", "execution_count": null, - "id": "227a7bf9", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -396,7 +396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ba23e12f", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -409,7 +409,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60eccb16", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -425,7 +425,7 @@ }, { "cell_type": "markdown", - "id": "ccfa0b88", + "id": "29", "metadata": {}, "source": [ "## Exercises on creating an `ndarray`\n", @@ -438,7 +438,7 @@ { "cell_type": "code", "execution_count": null, - "id": "59ac3ddb", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -449,7 +449,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7f6299e9", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -464,7 +464,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d4a7f46f", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -479,7 +479,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7d21899b", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -493,7 +493,7 @@ }, { "cell_type": "markdown", - "id": "2a476b08", + "id": "34", "metadata": {}, "source": [ "## Specify the data type\n", @@ -506,7 +506,7 @@ { "cell_type": "code", "execution_count": null, - "id": "64e77b30", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -521,7 +521,7 @@ }, { "cell_type": "markdown", - "id": "7c03dd30", + "id": "36", "metadata": {}, "source": [ "Here we just passed the `dtype` argument to the `array()` function and specified the data type as `int`.\n", @@ -535,7 +535,7 @@ }, { "cell_type": "markdown", - "id": "11fbbc70", + "id": "37", "metadata": {}, "source": [ "## Exercises on specifying the data type.\n", @@ -548,7 +548,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21739566", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -559,7 +559,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6dc8d05c", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -574,7 +574,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4c9fa969", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -588,7 +588,7 @@ }, { "cell_type": "markdown", - "id": "19079568", + "id": "41", "metadata": {}, "source": [ "## Indexing, slicing, and iterating\n", @@ -603,7 +603,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85d425a5", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -613,7 +613,7 @@ }, { "cell_type": "markdown", - "id": "e4a99f2d", + "id": "43", "metadata": {}, "source": [ "Unlinke Python lists, multidimensional NumPy arrays can be accessed using a tuple of indices.\n", @@ -623,7 +623,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32449d62", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -633,7 +633,7 @@ }, { "cell_type": "markdown", - "id": "b04db8ff", + "id": "45", "metadata": {}, "source": [ "The slicing syntax is similar to that of Python lists.\n", @@ -643,7 +643,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46fed732", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -661,7 +661,7 @@ }, { "cell_type": "markdown", - "id": "30b25fca", + "id": "47", "metadata": {}, "source": [ "The multidimensional slicing syntax is the same except that we use a tuple of slices instead of a single slice.\n", @@ -672,7 +672,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6463b814", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -708,7 +708,7 @@ }, { "cell_type": "markdown", - "id": "0f397fdb", + "id": "49", "metadata": {}, "source": [ "It is OK to perform slicing only on some of the dimensions.\n", @@ -718,7 +718,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7573a885", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -735,7 +735,7 @@ }, { "cell_type": "markdown", - "id": "bf892ff4", + "id": "51", "metadata": {}, "source": [ "Keep in mind that the slice of an array is a view into the same data, so modifying it will modify the original array.\n", @@ -747,7 +747,7 @@ { "cell_type": "code", "execution_count": null, - "id": "806f0923", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -772,7 +772,7 @@ }, { "cell_type": "markdown", - "id": "387eaf7e", + "id": "53", "metadata": {}, "source": [ "Iterating over a NumPy array is similar to iterating over a Python list.\n", @@ -782,7 +782,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55235f6e", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -793,7 +793,7 @@ }, { "cell_type": "markdown", - "id": "e89cd055", + "id": "55", "metadata": {}, "source": [ "When the array is multidimensional, a for loop can be used to iterate over the first dimension of the array." @@ -802,7 +802,7 @@ { "cell_type": "code", "execution_count": null, - "id": "df68ecb3", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -813,7 +813,7 @@ }, { "cell_type": "markdown", - "id": "451dd067", + "id": "57", "metadata": {}, "source": [ "To iterate over each element of a multidimensional array, we can use the [`flat`](https://numpy.org/devdocs/reference/generated/numpy.ndarray.flat.html) attribute of the array." @@ -822,7 +822,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40327d75", + "id": "58", "metadata": {}, "outputs": [], "source": [ @@ -833,7 +833,7 @@ }, { "cell_type": "markdown", - "id": "14467a88", + "id": "59", "metadata": {}, "source": [ "## Exercises on indexing, slicing, and iterating\n", @@ -847,7 +847,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8f12aca3", + "id": "60", "metadata": {}, "outputs": [], "source": [ @@ -857,7 +857,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3edc0b7f", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -872,7 +872,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d7c8ea28", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -887,7 +887,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1c956033", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -903,7 +903,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cf20a779", + "id": "64", "metadata": {}, "outputs": [], "source": [ @@ -917,7 +917,7 @@ }, { "cell_type": "markdown", - "id": "e4f1b6ff", + "id": "65", "metadata": {}, "source": [ "## Other useful attributes of `ndarray`\n", @@ -937,7 +937,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aca0e339", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -952,7 +952,7 @@ }, { "cell_type": "markdown", - "id": "d69b3efd", + "id": "67", "metadata": {}, "source": [ "For more attributes of the `ndarray` object, check out the [official documentation](https://numpy.org/devdocs/reference/arrays.ndarray.html#array-attributes)." @@ -960,7 +960,7 @@ }, { "cell_type": "markdown", - "id": "6420b723", + "id": "68", "metadata": {}, "source": [ "## Useful methods of `ndarray`\n", @@ -992,7 +992,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d30d81e0", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -1026,7 +1026,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ce062c05", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -1076,7 +1076,7 @@ }, { "cell_type": "markdown", - "id": "c02d89fb", + "id": "71", "metadata": {}, "source": [ "### The `axis` argument.\n", @@ -1092,7 +1092,7 @@ { "cell_type": "code", "execution_count": null, - "id": "836b142d", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -1113,7 +1113,7 @@ }, { "cell_type": "markdown", - "id": "18d1c523", + "id": "73", "metadata": {}, "source": [ "In other words, the value of the `axis` argument tells us which axis will be collapsed.\n", @@ -1125,7 +1125,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aa81dee2", + "id": "74", "metadata": {}, "outputs": [], "source": [ @@ -1150,7 +1150,7 @@ }, { "cell_type": "markdown", - "id": "a5d7d33e", + "id": "75", "metadata": {}, "source": [ "# Vectorized operations\n", @@ -1164,7 +1164,7 @@ }, { "cell_type": "markdown", - "id": "fd41b061", + "id": "76", "metadata": {}, "source": [ "## Arithmetic operations\n", @@ -1176,7 +1176,7 @@ { "cell_type": "code", "execution_count": null, - "id": "97f3556b", + "id": "77", "metadata": {}, "outputs": [], "source": [ @@ -1203,7 +1203,7 @@ }, { "cell_type": "markdown", - "id": "a4de8f6b", + "id": "78", "metadata": {}, "source": [ "All arithmetic operators that are available for Python numbers are also available for NumPy arrays.\n", @@ -1217,7 +1217,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7d1a9ddc", + "id": "79", "metadata": {}, "outputs": [], "source": [ @@ -1228,7 +1228,7 @@ }, { "cell_type": "markdown", - "id": "27ef8dda", + "id": "80", "metadata": {}, "source": [ "## Comparison operators\n", @@ -1242,7 +1242,7 @@ { "cell_type": "code", "execution_count": null, - "id": "339d2589", + "id": "81", "metadata": {}, "outputs": [], "source": [ @@ -1266,7 +1266,7 @@ }, { "cell_type": "markdown", - "id": "1551676c", + "id": "82", "metadata": {}, "source": [ "Again, all comparison operators that are available for Python numbers are also available for NumPy arrays." @@ -1274,7 +1274,7 @@ }, { "cell_type": "markdown", - "id": "fafff00c", + "id": "83", "metadata": {}, "source": [ "### Use comparison operators in `if` statements.\n", @@ -1288,7 +1288,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ae006c33", + "id": "84", "metadata": {}, "outputs": [], "source": [ @@ -1298,7 +1298,7 @@ }, { "cell_type": "markdown", - "id": "5844630b", + "id": "85", "metadata": {}, "source": [ "NumPy complains that the truth value of an array with more than one element is ambiguous.\n", @@ -1310,7 +1310,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d3e4d5eb", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -1323,7 +1323,7 @@ }, { "cell_type": "markdown", - "id": "cf91ca1c", + "id": "87", "metadata": {}, "source": [ "## Vectorized operations with scalars\n", @@ -1337,7 +1337,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8919240a", + "id": "88", "metadata": {}, "outputs": [], "source": [ @@ -1372,7 +1372,7 @@ }, { "cell_type": "markdown", - "id": "4b9de291", + "id": "89", "metadata": {}, "source": [ "## Mathematical functions\n", @@ -1387,7 +1387,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7ba505e1", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1419,7 +1419,7 @@ }, { "cell_type": "markdown", - "id": "ad15e9ce", + "id": "91", "metadata": {}, "source": [ "## Exercises on vectorized operations\n", @@ -1431,7 +1431,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f084de66", + "id": "92", "metadata": {}, "outputs": [], "source": [ @@ -1441,7 +1441,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8f35eac4", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1458,7 +1458,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e5a7d8c6", + "id": "94", "metadata": {}, "outputs": [], "source": [ @@ -1472,7 +1472,7 @@ }, { "cell_type": "markdown", - "id": "929c4229", + "id": "95", "metadata": {}, "source": [ "# NumPy routines\n", @@ -1486,7 +1486,7 @@ }, { "cell_type": "markdown", - "id": "2ca2a911", + "id": "96", "metadata": {}, "source": [ "## Numerical integrals and derivatives\n", @@ -1498,7 +1498,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7ceae825", + "id": "97", "metadata": {}, "outputs": [], "source": [ @@ -1520,7 +1520,7 @@ }, { "cell_type": "markdown", - "id": "2c0519a8", + "id": "98", "metadata": {}, "source": [ "To compute the numerical derivative, we will use the [`gradient()`](https://numpy.org/devdocs/reference/generated/numpy.gradient.html) function.\n", @@ -1530,7 +1530,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5e1336f7", + "id": "99", "metadata": {}, "outputs": [], "source": [ @@ -1542,7 +1542,7 @@ }, { "cell_type": "markdown", - "id": "0b3fbe89", + "id": "100", "metadata": {}, "source": [ "We can do that because the integral of a function is the cumulative sum of the function with infinitesimal step size.\n", @@ -1566,7 +1566,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f3d4fa62", + "id": "101", "metadata": {}, "outputs": [], "source": [ @@ -1578,7 +1578,7 @@ }, { "cell_type": "markdown", - "id": "61926fe9", + "id": "102", "metadata": {}, "source": [ "## 2D functions\n" @@ -1586,7 +1586,7 @@ }, { "cell_type": "markdown", - "id": "246969c3", + "id": "103", "metadata": {}, "source": [ "## meshgrid\n", @@ -1608,7 +1608,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4710b87a", + "id": "104", "metadata": {}, "outputs": [], "source": [ @@ -1619,7 +1619,7 @@ }, { "cell_type": "markdown", - "id": "11f57e18", + "id": "105", "metadata": {}, "source": [ "We deliberaly used different sizes for `x` and `y` to let NumPy explicitly tell us that something is wrong.\n", @@ -1691,7 +1691,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a6925978", + "id": "106", "metadata": {}, "outputs": [], "source": [ @@ -1709,7 +1709,7 @@ }, { "cell_type": "markdown", - "id": "0bdcff53", + "id": "107", "metadata": {}, "source": [ "Now, we can use the `xx` and `yy` arrays to compute the values of the `f(x, y)` function:" @@ -1718,7 +1718,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b23075f", + "id": "108", "metadata": {}, "outputs": [], "source": [ @@ -1730,7 +1730,7 @@ }, { "cell_type": "markdown", - "id": "f77f3568", + "id": "109", "metadata": {}, "source": [ "## Compute gradients of a 2D function\n", @@ -1746,7 +1746,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b563c02b", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1759,7 +1759,7 @@ }, { "cell_type": "markdown", - "id": "4c04fe46", + "id": "111", "metadata": {}, "source": [ "The gradient function returns a list of arrays, one for each dimension of the grid.\n", @@ -1768,7 +1768,7 @@ }, { "cell_type": "markdown", - "id": "28cf1124", + "id": "112", "metadata": {}, "source": [ "## Linear algebra\n", @@ -1782,7 +1782,7 @@ }, { "cell_type": "markdown", - "id": "18bb9285", + "id": "113", "metadata": {}, "source": [ "### Matrix multiplication\n", @@ -1794,7 +1794,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3cd08a3b", + "id": "114", "metadata": {}, "outputs": [], "source": [ @@ -1811,7 +1811,7 @@ }, { "cell_type": "markdown", - "id": "39cec3ec", + "id": "115", "metadata": {}, "source": [ "### System of linear equations\n", @@ -1831,7 +1831,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77c2f4d8", + "id": "116", "metadata": {}, "outputs": [], "source": [ @@ -1848,7 +1848,7 @@ }, { "cell_type": "markdown", - "id": "6c484888", + "id": "117", "metadata": {}, "source": [ "### Finding eigenvalues and eigenvectors\n", @@ -1871,7 +1871,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3cafaeb4", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1892,7 +1892,7 @@ }, { "cell_type": "markdown", - "id": "c72e1b3b", + "id": "119", "metadata": {}, "source": [ "## Exercises on NumPy routines\n", @@ -1914,7 +1914,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6557dc25", + "id": "120", "metadata": {}, "outputs": [], "source": [ @@ -1924,7 +1924,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e4c1c43b", + "id": "121", "metadata": {}, "outputs": [], "source": [ @@ -1940,7 +1940,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bf910df2", + "id": "122", "metadata": {}, "outputs": [], "source": [ @@ -1954,7 +1954,7 @@ }, { "cell_type": "markdown", - "id": "9ee5f460", + "id": "123", "metadata": {}, "source": [ "# Advanced indexing\n", @@ -1970,7 +1970,7 @@ { "cell_type": "code", "execution_count": null, - "id": "842e829c", + "id": "124", "metadata": {}, "outputs": [], "source": [ @@ -1987,7 +1987,7 @@ }, { "cell_type": "markdown", - "id": "b4938098", + "id": "125", "metadata": {}, "source": [ "Do not forget that tuples are used to access elements of multidimensional arrays, they cannot be used to index 1D arrays." @@ -1996,7 +1996,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2a603154", + "id": "126", "metadata": {}, "outputs": [], "source": [ @@ -2011,7 +2011,7 @@ }, { "cell_type": "markdown", - "id": "f33f6b6c", + "id": "127", "metadata": {}, "source": [ "## Indexing with an array of integers\n", @@ -2023,7 +2023,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33c8b116", + "id": "128", "metadata": {}, "outputs": [], "source": [ @@ -2036,7 +2036,7 @@ }, { "cell_type": "markdown", - "id": "f469cb3c", + "id": "129", "metadata": {}, "source": [ "When dealing the multidimensional arrays, a single array of integers refers to the first dimension of the array.\n", @@ -2048,7 +2048,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2eeccb5c", + "id": "130", "metadata": {}, "outputs": [], "source": [ @@ -2065,7 +2065,7 @@ }, { "cell_type": "markdown", - "id": "a05f4b5a", + "id": "131", "metadata": {}, "source": [ "We can also give indexes for each dimension of the array.\n", @@ -2075,7 +2075,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57b9d1e2", + "id": "132", "metadata": {}, "outputs": [], "source": [ @@ -2096,7 +2096,7 @@ }, { "cell_type": "markdown", - "id": "291328d1", + "id": "133", "metadata": {}, "source": [ "## Indexing and assigning values\n", @@ -2111,7 +2111,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e023346d", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -2127,7 +2127,7 @@ }, { "cell_type": "markdown", - "id": "d6fc8424", + "id": "135", "metadata": {}, "source": [ "Instead, if we assign the result of the indexing to a new variable, we will get a copy of the original array, and the original array will remain intact." @@ -2136,7 +2136,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ebf1e2d7", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -2156,7 +2156,7 @@ }, { "cell_type": "markdown", - "id": "44ef7e12", + "id": "137", "metadata": {}, "source": [ "## Indexing with boolean arrays\n", @@ -2169,7 +2169,7 @@ { "cell_type": "code", "execution_count": null, - "id": "82731481", + "id": "138", "metadata": {}, "outputs": [], "source": [ @@ -2183,7 +2183,7 @@ }, { "cell_type": "markdown", - "id": "c6e8808b", + "id": "139", "metadata": {}, "source": [ "Explicitly specifying a boolean array is not very useful.\n", @@ -2194,7 +2194,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fdb30f33", + "id": "140", "metadata": {}, "outputs": [], "source": [ @@ -2216,7 +2216,7 @@ }, { "cell_type": "markdown", - "id": "d591fecd", + "id": "141", "metadata": {}, "source": [ "# Broadcasting\n", @@ -2250,7 +2250,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9c9c65d1", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -2271,7 +2271,7 @@ }, { "cell_type": "markdown", - "id": "043faf3d", + "id": "143", "metadata": {}, "source": [ "## Second example: adding dimensions\n", @@ -2285,7 +2285,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8eedc915", + "id": "144", "metadata": {}, "outputs": [], "source": [ @@ -2299,7 +2299,7 @@ }, { "cell_type": "markdown", - "id": "e50057ec", + "id": "145", "metadata": {}, "source": [ "# Exercises" @@ -2307,7 +2307,7 @@ }, { "cell_type": "markdown", - "id": "f2c05018", + "id": "146", "metadata": {}, "source": [ "## Sum numbers from 0 to 10000 🌶️\n", @@ -2318,7 +2318,7 @@ { "cell_type": "code", "execution_count": null, - "id": "865bcd56", + "id": "147", "metadata": {}, "outputs": [], "source": [ @@ -2328,7 +2328,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3a46ab02", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -2343,7 +2343,7 @@ }, { "cell_type": "markdown", - "id": "39bf8d5c", + "id": "149", "metadata": {}, "source": [ "## Investigate a mathematical function 🌶️🌶️:\n", @@ -2358,7 +2358,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5854a50b", + "id": "150", "metadata": {}, "outputs": [], "source": [ @@ -2368,7 +2368,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47fe640b", + "id": "151", "metadata": {}, "outputs": [], "source": [ @@ -2378,7 +2378,7 @@ { "cell_type": "code", "execution_count": null, - "id": "689f23d7", + "id": "152", "metadata": {}, "outputs": [], "source": [ @@ -2396,7 +2396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f5fbc53e", + "id": "153", "metadata": {}, "outputs": [], "source": [ @@ -2412,7 +2412,7 @@ }, { "cell_type": "markdown", - "id": "3d1bde44", + "id": "154", "metadata": {}, "source": [ "## Exercise flower petal 🌶️🌶️🌶️:\n", @@ -2425,7 +2425,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1a882dd9", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -2443,7 +2443,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b13b696d", + "id": "156", "metadata": {}, "outputs": [], "source": [ @@ -2453,7 +2453,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5704ba27", + "id": "157", "metadata": {}, "outputs": [], "source": [ @@ -2470,7 +2470,7 @@ { "cell_type": "code", "execution_count": null, - "id": "debcfe5e", + "id": "158", "metadata": {}, "outputs": [], "source": [ diff --git a/library_pandas.ipynb b/library_pandas.ipynb index aabb493a..e929b6cf 100644 --- a/library_pandas.ipynb +++ b/library_pandas.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "a03ea0d4-7724-4e00-b447-0b3f84c88396", + "id": "0", "metadata": {}, "source": [ "# Pandas 🐼" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "9a8972a3-f9d8-48fe-a7d3-8c5539afa747", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -86,7 +86,7 @@ }, { "cell_type": "markdown", - "id": "2a054a4c-a2d0-4bd6-9bd7-b32c40364ae4", + "id": "2", "metadata": {}, "source": [ "# Introduction\n", @@ -95,7 +95,7 @@ }, { "cell_type": "markdown", - "id": "2a123b2d-64cd-43f7-9255-567ca8d817d1", + "id": "3", "metadata": {}, "source": [ "### What is Pandas?\n", @@ -111,7 +111,7 @@ }, { "cell_type": "markdown", - "id": "64075e7a-3ca7-41dc-b105-bf2b50c13541", + "id": "4", "metadata": {}, "source": [ "### Why We Need Pandas with Python\n", @@ -128,7 +128,7 @@ }, { "cell_type": "markdown", - "id": "a27059d1-124b-4247-ae63-55601f7e4cb6", + "id": "5", "metadata": {}, "source": [ "### When and Why It's Used\n", @@ -144,7 +144,7 @@ }, { "cell_type": "markdown", - "id": "e2422a58-51f0-46e7-814c-5c7966b0d578", + "id": "6", "metadata": {}, "source": [ "### Pandas Performance\n", @@ -159,7 +159,7 @@ }, { "cell_type": "markdown", - "id": "d69e4f81-6f20-44e4-9e13-4fb514522782", + "id": "7", "metadata": {}, "source": [ "### Alternatives and When They Are Better\n", @@ -175,7 +175,7 @@ }, { "cell_type": "markdown", - "id": "0de7aebe-e8c7-48e3-a801-acb76f6be285", + "id": "8", "metadata": {}, "source": [ "---" @@ -183,7 +183,7 @@ }, { "cell_type": "markdown", - "id": "797684bc-adc0-4341-82b8-f8cfc84a383e", + "id": "9", "metadata": { "jp-MarkdownHeadingCollapsed": true }, @@ -197,7 +197,7 @@ }, { "cell_type": "markdown", - "id": "a8cef29a-cf96-41ea-8c99-0045237ca63c", + "id": "10", "metadata": {}, "source": [ "---" @@ -205,7 +205,7 @@ }, { "cell_type": "markdown", - "id": "ec15fe23-17cc-479f-abd0-adeaf617b2e2", + "id": "11", "metadata": {}, "source": [ "# Working with Pandas `DataFrame`" @@ -213,7 +213,7 @@ }, { "cell_type": "markdown", - "id": "4aa3c0c3-33c0-4062-a3d6-60e401d7486a", + "id": "12", "metadata": {}, "source": [ "## Pandas Data Structures" @@ -221,7 +221,7 @@ }, { "cell_type": "markdown", - "id": "78e5e05e-d681-4e01-9f79-b9dc1551060c", + "id": "13", "metadata": {}, "source": [ "\n", @@ -230,7 +230,7 @@ }, { "cell_type": "markdown", - "id": "5018ca94-bd00-465e-a423-77668ccf303b", + "id": "14", "metadata": {}, "source": [ "### Working with NumPy Arrays\n", @@ -240,7 +240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2d6609f1-a037-41ac-9d40-9d84948b3144", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -255,7 +255,7 @@ }, { "cell_type": "markdown", - "id": "a52faac6-686a-45ed-adeb-13ed264f3746", + "id": "16", "metadata": {}, "source": [ "We can find the dimensions with the `shape` attribute:" @@ -264,7 +264,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b1d423ff-7558-4a0b-b02a-c1ab46fa5c27", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -273,7 +273,7 @@ }, { "cell_type": "markdown", - "id": "64774481-9c6e-4605-a237-660fdeabfede", + "id": "18", "metadata": {}, "source": [ "We can find the data types with the `dtype` attribute:" @@ -282,7 +282,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e9e95237-eb16-403b-9ea6-43e23f100f7f", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -291,7 +291,7 @@ }, { "cell_type": "markdown", - "id": "d52dfa6b-8822-4c32-af12-98674d6e5941", + "id": "20", "metadata": {}, "source": [ "Each element in the array corresponds to a row from the CSV file. Unlike lists that can hold multiple data types, NumPy arrays are limited to one, enabling quick, vectorized actions. The data import resulted in an array of `numpy.void` objects, designed to handle various types. This occurs as each row contains diverse data types: four strings, one float, and one integer. Consequently, we miss out on the performance benefits NumPy offers for arrays with uniform data types.\n", @@ -302,7 +302,7 @@ { "cell_type": "code", "execution_count": null, - "id": "db37861f-d2dd-4bef-993e-19a2b054fbf2", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -312,7 +312,7 @@ }, { "cell_type": "markdown", - "id": "7765125b-dbfd-45ed-8a2c-50f6a49adb2b", + "id": "22", "metadata": {}, "source": [ "If we, instead, create a NumPy array for each column, this operation is much easier (and more efficient) to perform. We can use a **[dictionary comprehension](https://www.python.org/dev/peps/pep-0274/)** to make a dictionary where the keys are the column names and the values are NumPy arrays of the data:" @@ -321,7 +321,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12a1ff1f-21f5-4703-baf1-e27b7e5f0a59", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -334,7 +334,7 @@ }, { "cell_type": "markdown", - "id": "286d03eb-3a04-4055-aa57-01b112669ce0", + "id": "24", "metadata": {}, "source": [ "Grabbing the maximum magnitude is now simply a matter of selecting the `mag` key and calling the `max()` method. This is nearly twice as fast as the list comprehension implementation when dealing with just 5 entries, imagine how much worse the first attempt will perform on large data sets:" @@ -343,7 +343,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b205f482-d065-4ad6-a456-c0855690de03", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -353,7 +353,7 @@ }, { "cell_type": "markdown", - "id": "fa5e68fd-65d6-48d8-a1b6-0d3b3c8f8151", + "id": "26", "metadata": {}, "source": [ "However, this representation has other issues. Say we wanted to grab all the information for the earthquake with the maximum magnitude, how would we go about that? We would need to find the index of the maximum and then for each of the keys in the dictionary grab that index:" @@ -362,7 +362,7 @@ { "cell_type": "code", "execution_count": null, - "id": "467ff128-69ab-40ec-9e9c-866a5100f77b", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -374,7 +374,7 @@ }, { "cell_type": "markdown", - "id": "cf67e3a9-2fcf-4bbc-8cab-49379b663e43", + "id": "28", "metadata": {}, "source": [ "We now have a NumPy array consisting solely of strings, converting our numerical values into this format and reverting to the earlier setup. Additionally, if we aim to sort the data by magnitude in ascending order, the initial format requires sorting the rows based on the third index. In the second format, we need to establish the sorting order based on the `mag` column and then rearrange all other arrays accordingly. Handling multiple NumPy arrays with different data types simultaneously can be challenging. This is where `pandas` comes into play, enhancing the ease of working with NumPy arrays. Let's begin delving into `pandas` by understanding its data structure." @@ -382,7 +382,7 @@ }, { "cell_type": "markdown", - "id": "e1f02e36-1531-46af-953a-179ccf8b01b1", + "id": "29", "metadata": {}, "source": [ "### `Series`\n", @@ -392,7 +392,7 @@ { "cell_type": "code", "execution_count": null, - "id": "680b4b52-b3d9-421e-88e1-4d19935ea384", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -404,7 +404,7 @@ }, { "cell_type": "markdown", - "id": "491b639a-4102-4b01-9e2d-6dc8feacf29f", + "id": "31", "metadata": {}, "source": [ "Here are some commonly used attributes with `Series` objects:\n", @@ -429,7 +429,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5d061fb7-8efe-44cf-9752-9e710a7c2436", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -438,7 +438,7 @@ }, { "cell_type": "markdown", - "id": "f9474613-7dde-4bc9-a12f-bda893948085", + "id": "33", "metadata": {}, "source": [ "**Getting the data type**\n", @@ -450,7 +450,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bc38c3f3-e182-4349-b6e8-d8e5e450a6d9", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -459,7 +459,7 @@ }, { "cell_type": "markdown", - "id": "e9f9d9e6-3ea2-47e4-ba1c-5e3ca840a084", + "id": "35", "metadata": {}, "source": [ "**Getting the dimensions of the series**\n", @@ -471,7 +471,7 @@ { "cell_type": "code", "execution_count": null, - "id": "999677ee-f317-4771-9348-65ec2fd2411d", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -480,7 +480,7 @@ }, { "cell_type": "markdown", - "id": "a566722c-7fd2-4256-82e4-78d09e3d42e2", + "id": "37", "metadata": {}, "source": [ "**Isolating the values from the series**\n", @@ -491,7 +491,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40cfbf79-086c-40c1-96a7-532e9620d1b4", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -500,7 +500,7 @@ }, { "cell_type": "markdown", - "id": "54f9a8a6-6224-44d9-99fa-1a1d726fdecb", + "id": "39", "metadata": {}, "source": [ "### `Index`\n", @@ -510,7 +510,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cacfab39-539a-482c-8307-a922a58cac12", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -520,7 +520,7 @@ }, { "cell_type": "markdown", - "id": "24bdf54f-58c0-4d8e-ab8a-5d8a5b138c3f", + "id": "41", "metadata": {}, "source": [ "As with `Series` objects, we can access the underlying data via the `values` attribute. Note that this `Index` object is also built on top of a NumPy array:" @@ -529,7 +529,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2f400e54-1f0a-4ecb-9e83-d1deb64a44ef", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -538,7 +538,7 @@ }, { "cell_type": "markdown", - "id": "d5a27615-81b6-4afd-afde-6df0f991e64c", + "id": "43", "metadata": {}, "source": [ "Here are some commonly used attributes with `Index` objects:\n", @@ -557,7 +557,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14c9e50f-b199-41da-b6b3-179dec13836c", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -566,7 +566,7 @@ }, { "cell_type": "markdown", - "id": "f0f5126c-7297-4502-b99f-3b320db48276", + "id": "45", "metadata": {}, "source": [ "Same for the dimensions:" @@ -575,7 +575,7 @@ { "cell_type": "code", "execution_count": null, - "id": "45ca8016-1534-428b-a4b3-e98cb90a9509", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -584,7 +584,7 @@ }, { "cell_type": "markdown", - "id": "4ac953a0-f9ae-44f0-8d24-edddddda8fa2", + "id": "47", "metadata": {}, "source": [ "We can check if the values are unique:" @@ -593,7 +593,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85271f65-2fc0-4445-8fa7-19c20ead6822", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -602,7 +602,7 @@ }, { "cell_type": "markdown", - "id": "ad90acc8-afdc-46ce-9293-4ea9b2ebe7c2", + "id": "49", "metadata": {}, "source": [ "With NumPy we can perform arithmetic operations element-wise between arrays:" @@ -611,7 +611,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c24956ba-6b41-44af-9183-75fcfe7b4da0", + "id": "50", "metadata": {}, "outputs": [], "source": [ @@ -620,7 +620,7 @@ }, { "cell_type": "markdown", - "id": "f335ffb0-9c64-4c0f-997f-4e8e67d97250", + "id": "51", "metadata": {}, "source": [ "Pandas supports this as well, and the index determines how element-wise operations are performed. With addition, only the matching indices are summed:" @@ -629,7 +629,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0d2ca9ca-23bd-40c0-9ceb-069ec030c549", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -641,7 +641,7 @@ }, { "cell_type": "markdown", - "id": "a9137190-1232-41c4-8c21-bcfec3b042fb", + "id": "53", "metadata": {}, "source": [ "We aren't limited to the integer indices of list-like structures, and we can label our rows. The labels can be altered at any time and be things like dates or even another column. In chapter 3, we will discuss how to perform some operations on the index in order to change it. Then, in chapter 4, we will use the index for operations merging data and aggregating it.\n", @@ -650,7 +650,7 @@ }, { "cell_type": "markdown", - "id": "e0478136-bea2-408f-ba50-03b08ab09d1f", + "id": "54", "metadata": {}, "source": [ "### `DataFrame`\n", @@ -664,7 +664,7 @@ { "cell_type": "code", "execution_count": null, - "id": "046a2d17-e295-4dbd-8f1f-4012f548c9ed", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -678,7 +678,7 @@ }, { "cell_type": "markdown", - "id": "a075d3db-37d2-4158-b356-44b022b92d5e", + "id": "56", "metadata": {}, "source": [ "We can check the type of the underlying data with `dtypes` (note that it is not `dtype` as with `Series` and `Index` objects since each column will have its own data type):" @@ -687,7 +687,7 @@ { "cell_type": "code", "execution_count": null, - "id": "afafa3a7-85d2-4cfd-bf6c-bea6b94eed53", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -696,7 +696,7 @@ }, { "cell_type": "markdown", - "id": "3ed82b8e-69bf-4124-9cfe-c9e68fd0fd5f", + "id": "58", "metadata": {}, "source": [ "We can get the underlying data with the `values` attribute. Note that this looks very similar to our initial NumPy representation:" @@ -705,7 +705,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c4431cf4-362e-42ce-8c8c-9ee5e26a802e", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -714,7 +714,7 @@ }, { "cell_type": "markdown", - "id": "66189f0a-336e-4a9a-8cce-78e8696ae696", + "id": "60", "metadata": {}, "source": [ "We can isolate the columns with the `columns` attribute. Notice that the columns are actually an `Index` object just on a different axis (columns are the horizontal index while rows are the vertical index)." @@ -723,7 +723,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cacc1ca3-3748-40c3-b539-3231ceb9015e", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -732,7 +732,7 @@ }, { "cell_type": "markdown", - "id": "f6a56716-87a8-4db2-a5ed-452a20fcf8ed", + "id": "62", "metadata": {}, "source": [ "Here are some commonly used attributes:\n", @@ -752,7 +752,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28429812-d4ec-4d32-bcb2-996a63a36400", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -761,7 +761,7 @@ }, { "cell_type": "markdown", - "id": "6089e141-0bfe-4632-adec-7ea03aead2c5", + "id": "64", "metadata": {}, "source": [ "As with both `Series` and `Index` objects, we can get the dimensions of the dataframe with the `shape` attribute. The result is of the form `(nrows, ncols)`. Our dataframe has 5 rows and 6 columns:" @@ -770,7 +770,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21fbe133-ead3-4df1-bec2-343ca2095bfe", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -779,7 +779,7 @@ }, { "cell_type": "markdown", - "id": "fa971a7a-1274-43a8-a053-e33f16fcc084", + "id": "66", "metadata": {}, "source": [ "Pandas allows arithmetic operations on dataframes, matching both index and column for execution.\n", @@ -791,7 +791,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0402961e-aef0-4078-899c-2679a127b4e0", + "id": "67", "metadata": {}, "outputs": [], "source": [ @@ -800,7 +800,7 @@ }, { "cell_type": "markdown", - "id": "992e9db9-f64a-450e-8da4-ef8382964aa3", + "id": "68", "metadata": {}, "source": [ "## Creating `DataFrame` objects" @@ -809,7 +809,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b579e952-10ca-41e4-b71a-4b424030abf8", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -820,7 +820,7 @@ }, { "cell_type": "markdown", - "id": "23e689c8-7284-4687-a575-f976b18bddb6", + "id": "70", "metadata": {}, "source": [ "### Creating a `Series` object" @@ -829,7 +829,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f85744c0-1a3b-4d7a-99b7-722ad0aa43fc", + "id": "71", "metadata": {}, "outputs": [], "source": [ @@ -839,7 +839,7 @@ }, { "cell_type": "markdown", - "id": "e2079f44-2587-4c71-a6c9-a8b5568c00a2", + "id": "72", "metadata": {}, "source": [ "### Creating a `DataFrame` object from a `Series` object\n", @@ -849,7 +849,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6270adc1-421a-4b6c-a8cc-1378440de20c", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -858,7 +858,7 @@ }, { "cell_type": "markdown", - "id": "83a5a314-908b-4a7c-ae53-14aba193579e", + "id": "74", "metadata": {}, "source": [ "### Creating a `DataFrame` from Python Data Structures" @@ -866,7 +866,7 @@ }, { "cell_type": "markdown", - "id": "edab2524-8656-4147-8027-003f027f11ba", + "id": "75", "metadata": {}, "source": [ "#### From a dictionary of list-like structures\n", @@ -877,7 +877,7 @@ { "cell_type": "code", "execution_count": null, - "id": "276aca56-ac26-42cf-a777-a384400d07c0", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -899,7 +899,7 @@ }, { "cell_type": "markdown", - "id": "548b76bd-b52b-46a6-9196-bab36ceeacaa", + "id": "77", "metadata": {}, "source": [ "#### From a list of dictionaries" @@ -908,7 +908,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1e40cc1c-f003-4959-9258-3517df72ddae", + "id": "78", "metadata": {}, "outputs": [], "source": [ @@ -921,7 +921,7 @@ }, { "cell_type": "markdown", - "id": "4c8cd8bf-2f7a-4464-8ebe-2e4ac9d51ca1", + "id": "79", "metadata": {}, "source": [ "#### From a list of tuples" @@ -930,7 +930,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a72713c0-5a24-4985-b031-616c2806fe4e", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -941,7 +941,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3b93eede-5142-4ce6-acb5-f0d77b23a857", + "id": "81", "metadata": {}, "outputs": [], "source": [ @@ -953,7 +953,7 @@ }, { "cell_type": "markdown", - "id": "faf31692-8b8c-4310-a477-8b6a70b0c5b9", + "id": "82", "metadata": {}, "source": [ "#### From a NumPy array" @@ -962,7 +962,7 @@ { "cell_type": "code", "execution_count": null, - "id": "683b83d2-99f2-421b-b982-0b73034ed6c0", + "id": "83", "metadata": {}, "outputs": [], "source": [ @@ -979,7 +979,7 @@ }, { "cell_type": "markdown", - "id": "3d9f9ce3-7dbe-44ed-8af7-d3fd4adf9aa6", + "id": "84", "metadata": {}, "source": [ "## Creating a `DataFrame` object from the contents of a CSV File" @@ -987,7 +987,7 @@ }, { "cell_type": "markdown", - "id": "2fafe748-4202-4bb3-89a2-19962b735c5e", + "id": "85", "metadata": {}, "source": [ "### Finding information on the file before reading it in\n", @@ -999,7 +999,7 @@ { "cell_type": "code", "execution_count": null, - "id": "256e6c34-ce3f-4b5e-b83b-4a1edc490db3", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -1008,7 +1008,7 @@ }, { "cell_type": "markdown", - "id": "c60a6952-60d3-468d-8c92-529ee861dd82", + "id": "87", "metadata": {}, "source": [ "**Windows users**: if the above doesn't work for you (depends on your setup), then use this instead:\n", @@ -1026,7 +1026,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3c024ae1-8f94-4752-92c9-7c71082adc90", + "id": "88", "metadata": {}, "outputs": [], "source": [ @@ -1035,7 +1035,7 @@ }, { "cell_type": "markdown", - "id": "fcc6ffa8-6d8c-475d-b5d3-8265d74de456", + "id": "89", "metadata": {}, "source": [ "**Windows users**: if the above doesn't work for you (depends on your setup), then use this instead:\n", @@ -1050,7 +1050,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0e35aeff-f7de-49d3-b917-0b3fb1e62f8c", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1060,7 +1060,7 @@ }, { "cell_type": "markdown", - "id": "29f9918a-aae0-4152-8650-2fbe8f925218", + "id": "91", "metadata": {}, "source": [ "**Windows users**: if the above doesn't work for you (depends on your setup), then use this instead:\n", @@ -1073,7 +1073,7 @@ }, { "cell_type": "markdown", - "id": "0e2fe223-af7a-4b0a-be85-0325c82c11e4", + "id": "92", "metadata": {}, "source": [ "#### Examining a few rows\n", @@ -1084,7 +1084,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4fc213fb-e153-4abd-bb85-180bacdf1ecc", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1093,7 +1093,7 @@ }, { "cell_type": "markdown", - "id": "c76669b2-07f4-4fb4-9ace-7317201ee467", + "id": "94", "metadata": {}, "source": [ "**Windows users**: if the above doesn't work for you (depends on your setup), then use this instead:\n", @@ -1112,7 +1112,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60abd901-4049-47b3-a325-34b1025322ad", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1121,7 +1121,7 @@ }, { "cell_type": "markdown", - "id": "1cdedb86-3fd5-4e8c-9f21-8587319bcc6d", + "id": "96", "metadata": {}, "source": [ "**Windows users**: if the above doesn't work for you (depends on your setup), then use this instead:\n", @@ -1148,7 +1148,7 @@ }, { "cell_type": "markdown", - "id": "906c7428-4d23-488e-8ccb-bcf9a3cd1a6f", + "id": "97", "metadata": {}, "source": [ "#### Column count\n", @@ -1160,7 +1160,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e836e4be-8a96-4a71-b353-e5e05857e8ac", + "id": "98", "metadata": {}, "outputs": [], "source": [ @@ -1169,7 +1169,7 @@ }, { "cell_type": "markdown", - "id": "dfd1456f-bf06-4fb9-b836-97c8bbc8f530", + "id": "99", "metadata": {}, "source": [ "**Windows users**: if the above or below don't work for you (depends on your setup), then use this instead:\n", @@ -1186,7 +1186,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c1508d86-d650-4b00-941d-07edfd6332d4", + "id": "100", "metadata": {}, "outputs": [], "source": [ @@ -1196,7 +1196,7 @@ }, { "cell_type": "markdown", - "id": "adf72aed-d973-40b1-9c3b-8aae27d51962", + "id": "101", "metadata": {}, "source": [ "**Windows users**: if you had to use the alternatives above, consider trying out [Cygwin](https://www.cygwin.com) or [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/about).\n", @@ -1205,7 +1205,7 @@ }, { "cell_type": "markdown", - "id": "9965bc6d-d870-4911-a0da-1c6c9b3361a3", + "id": "102", "metadata": {}, "source": [ "### Reading in the file\n", @@ -1216,7 +1216,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61fe84f7-d525-47db-9ead-2c5dbc5e780f", + "id": "103", "metadata": {}, "outputs": [], "source": [ @@ -1225,7 +1225,7 @@ }, { "cell_type": "markdown", - "id": "e98518e7-cb75-4516-ac60-52aea28e919a", + "id": "104", "metadata": {}, "source": [ "Note that we can also pass in a URL. Let's read this same file from GitHub:" @@ -1234,7 +1234,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f1b72e26-347b-4039-913c-58b1aebc77cb", + "id": "105", "metadata": {}, "outputs": [], "source": [ @@ -1247,7 +1247,7 @@ }, { "cell_type": "markdown", - "id": "ba4bece1-e8cd-494e-b38c-448669a72cb9", + "id": "106", "metadata": {}, "source": [ "Pandas is usually very good at figuring out which options to use based on the input data, so we often won't need to add arguments to the call; however, there are many options available should we need them, some of which include the following:\n", @@ -1271,7 +1271,7 @@ }, { "cell_type": "markdown", - "id": "a0e38f10-1679-4988-97dc-60f7f3c00129", + "id": "107", "metadata": {}, "source": [ "### Writing a `DataFrame` Object to a CSV File\n", @@ -1282,7 +1282,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2149c9fd-0893-419e-804d-799f5fff71ec", + "id": "108", "metadata": {}, "outputs": [], "source": [ @@ -1291,7 +1291,7 @@ }, { "cell_type": "markdown", - "id": "7b73c4cf-7f99-43a3-9fce-5b1848c8a6dc", + "id": "109", "metadata": {}, "source": [ "## Writing a `DataFrame` Object to a Database\n", @@ -1301,7 +1301,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dcd1c022-e8f1-417a-ad49-c3584386224c", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1315,7 +1315,7 @@ }, { "cell_type": "markdown", - "id": "e241638c-a31e-4b3c-9d08-690287a850f0", + "id": "111", "metadata": {}, "source": [ "## Creating a `DataFrame` Object by Querying a Database\n", @@ -1325,7 +1325,7 @@ { "cell_type": "code", "execution_count": null, - "id": "073277f4-f497-43ea-a230-7d8a33de88c1", + "id": "112", "metadata": {}, "outputs": [], "source": [ @@ -1339,7 +1339,7 @@ }, { "cell_type": "markdown", - "id": "3b583efd-5522-44de-882e-fbb3e7c74ea5", + "id": "113", "metadata": {}, "source": [ "## Selecting data" @@ -1347,7 +1347,7 @@ }, { "cell_type": "markdown", - "id": "37017d6c-99b0-41e1-8488-d912a3505537", + "id": "114", "metadata": {}, "source": [ "We are going to use the `earthquakes.csv` file again, so let's read it in as a `DataFrame`:" @@ -1356,7 +1356,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76458e8f-d2db-4354-961a-2429e9a1027e", + "id": "115", "metadata": {}, "outputs": [], "source": [ @@ -1367,7 +1367,7 @@ }, { "cell_type": "markdown", - "id": "4236c9d5-5730-482a-97d2-14a973c53214", + "id": "116", "metadata": {}, "source": [ "### Selecting columns" @@ -1376,7 +1376,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e4e69410-af06-4d38-9b7b-5c91d865ebd7", + "id": "117", "metadata": {}, "outputs": [], "source": [ @@ -1385,7 +1385,7 @@ }, { "cell_type": "markdown", - "id": "28d46cc2-dcf9-48b8-8180-5d6f484e9b62", + "id": "118", "metadata": {}, "source": [ "Grab an entire column using dictionary syntax:" @@ -1394,7 +1394,7 @@ { "cell_type": "code", "execution_count": null, - "id": "af1db18c-1774-4993-8690-81583626e902", + "id": "119", "metadata": {}, "outputs": [], "source": [ @@ -1403,7 +1403,7 @@ }, { "cell_type": "markdown", - "id": "334c2fbd-cd2e-4857-aa83-2f4311ecae43", + "id": "120", "metadata": {}, "source": [ "Selecting multiple columns:" @@ -1412,7 +1412,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aebf4b35-0ed4-4a3f-8cd5-03da180d88a6", + "id": "121", "metadata": {}, "outputs": [], "source": [ @@ -1421,7 +1421,7 @@ }, { "cell_type": "markdown", - "id": "b9885703-c7f3-40b2-8f83-7423d9fa2036", + "id": "122", "metadata": {}, "source": [ "Selecting columns using list comprehensions and string operations:" @@ -1430,7 +1430,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b7a167f-c99a-40ff-8a90-832c8ac638a6", + "id": "123", "metadata": {}, "outputs": [], "source": [ @@ -1442,7 +1442,7 @@ }, { "cell_type": "markdown", - "id": "eb05e3ce-bc43-4581-baeb-a3ff34b63fc1", + "id": "124", "metadata": {}, "source": [ "Breaking down this example:\n", @@ -1452,7 +1452,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9ddddb53-86d7-4d99-92bf-757d62c00e09", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1461,7 +1461,7 @@ }, { "cell_type": "markdown", - "id": "8a5c4d46-c933-4d75-b6c2-779dd8a05484", + "id": "126", "metadata": {}, "source": [ "2. assembling the list" @@ -1470,7 +1470,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ce3abc6f-b687-49e5-8645-4f2fce719944", + "id": "127", "metadata": {}, "outputs": [], "source": [ @@ -1480,7 +1480,7 @@ }, { "cell_type": "markdown", - "id": "e0b6f6ca-def0-4167-93fc-86fce168399f", + "id": "128", "metadata": {}, "source": [ "3. using this list as the list of columns" @@ -1489,7 +1489,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b2fbeb79-dbcb-4d65-b54a-49a31663d06f", + "id": "129", "metadata": {}, "outputs": [], "source": [ @@ -1501,7 +1501,7 @@ }, { "cell_type": "markdown", - "id": "1de68113-525d-4d6f-a72f-addd7fdfde08", + "id": "130", "metadata": {}, "source": [ "### Slicing" @@ -1509,7 +1509,7 @@ }, { "cell_type": "markdown", - "id": "d70f40f5-9ad5-4282-b39e-9de90cde6965", + "id": "131", "metadata": {}, "source": [ "##### Selecting rows\n", @@ -1520,7 +1520,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5f5fdb52-08b9-40a3-a1d5-02149e501f89", + "id": "132", "metadata": {}, "outputs": [], "source": [ @@ -1529,7 +1529,7 @@ }, { "cell_type": "markdown", - "id": "8c1bd97d-2823-45ad-b312-effaadbf3ec5", + "id": "133", "metadata": {}, "source": [ "##### Selecting rows and columns with chaining" @@ -1538,7 +1538,7 @@ { "cell_type": "code", "execution_count": null, - "id": "986fa69d-dce9-471c-9421-3f6e990ee87a", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -1547,7 +1547,7 @@ }, { "cell_type": "markdown", - "id": "afc8c059-f99a-47a4-8b9a-22ba1caf695c", + "id": "135", "metadata": {}, "source": [ "Order doesn't matter here:" @@ -1556,7 +1556,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a1af174f-ebad-4d72-8bcb-9de14abb6b7d", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -1567,7 +1567,7 @@ }, { "cell_type": "markdown", - "id": "1cb74013-4e4c-4a48-a89d-5c4a7a18f3bb", + "id": "137", "metadata": {}, "source": [ "So we know how to select rows and columns, but can we update values? Well, if we try using what we have learned so far, we will see the following warning:" @@ -1576,7 +1576,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7e1a3b68-0b63-4f97-bede-815a9ca0b16b", + "id": "138", "metadata": {}, "outputs": [], "source": [ @@ -1585,7 +1585,7 @@ }, { "cell_type": "markdown", - "id": "cd08b8f9-f309-41ae-9fe7-1b5e955d49d3", + "id": "139", "metadata": {}, "source": [ "Note that it worked here, but `pandas` says we were setting a value on a copy of a slice and that we should use `loc` instead (see the following section):" @@ -1594,7 +1594,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2eb678f0-e065-4d92-9a1b-7689857f0165", + "id": "140", "metadata": {}, "outputs": [], "source": [ @@ -1603,7 +1603,7 @@ }, { "cell_type": "markdown", - "id": "e9920065-ddf4-47e6-aa91-1f13e78898ee", + "id": "141", "metadata": {}, "source": [ "### Indexing\n", @@ -1614,7 +1614,7 @@ { "cell_type": "code", "execution_count": null, - "id": "66b1d27f-ac3e-4b1c-aff4-a26bcd920431", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -1624,7 +1624,7 @@ }, { "cell_type": "markdown", - "id": "75355d24-2d0d-4560-a332-e9f5a0510d96", + "id": "143", "metadata": {}, "source": [ "#### Indexing with `loc`\n", @@ -1635,7 +1635,7 @@ { "cell_type": "code", "execution_count": null, - "id": "df260996-45f1-4c21-b70a-6ccd09d7df9b", + "id": "144", "metadata": {}, "outputs": [], "source": [ @@ -1644,7 +1644,7 @@ }, { "cell_type": "markdown", - "id": "733300ed-0cd0-4c8a-816d-63787fec1264", + "id": "145", "metadata": {}, "source": [ "We can use `loc` to select specific rows and columns without chaining. If we use row numbers with `loc`, they are now **inclusive** of the end index:" @@ -1653,7 +1653,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cdb8b272-c6ad-4108-9209-84bb122dcc22", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -1662,7 +1662,7 @@ }, { "cell_type": "markdown", - "id": "1c18e089-4e70-416e-b41f-911a52815b35", + "id": "147", "metadata": {}, "source": [ "#### Indexing with `iloc`\n", @@ -1672,7 +1672,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2f95e370-b608-4eac-b3f6-e2a3f874f889", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -1681,7 +1681,7 @@ }, { "cell_type": "markdown", - "id": "7f9b0d5e-d300-4dba-a160-e91edbfc16cb", + "id": "149", "metadata": {}, "source": [ "We can use slicing syntax with `iloc` for both rows and columns:" @@ -1690,7 +1690,7 @@ { "cell_type": "code", "execution_count": null, - "id": "da12233a-82cc-4935-bc95-239444b4b1d3", + "id": "150", "metadata": {}, "outputs": [], "source": [ @@ -1699,7 +1699,7 @@ }, { "cell_type": "markdown", - "id": "cd9e291f-0e90-4d59-95b7-d2d53a669fd9", + "id": "151", "metadata": {}, "source": [ "When using `loc`, we can slice on column names. This will be inclusive of the endpoint because you can't be expected to know what the next column name will be. As such, we have multiple ways to achieve the same end goal:" @@ -1708,7 +1708,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a0c11e4c-958a-4df3-b081-fac032bdfa9b", + "id": "152", "metadata": {}, "outputs": [], "source": [ @@ -1719,7 +1719,7 @@ }, { "cell_type": "markdown", - "id": "d57ffd62-5235-4688-b869-5a47f300f8c3", + "id": "153", "metadata": {}, "source": [ "#### Looking up scalar values\n", @@ -1729,7 +1729,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e0781b7d-9e11-4395-bbde-d7e7ea41c710", + "id": "154", "metadata": {}, "outputs": [], "source": [ @@ -1738,7 +1738,7 @@ }, { "cell_type": "markdown", - "id": "7346dd77-9117-4e8a-9d59-f4d2091fa34c", + "id": "155", "metadata": {}, "source": [ "...and `iat` with integer indices:" @@ -1747,7 +1747,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e785a2b2-bafe-41e8-a34a-c5da60aa981d", + "id": "156", "metadata": {}, "outputs": [], "source": [ @@ -1756,7 +1756,7 @@ }, { "cell_type": "markdown", - "id": "e06d5262-f91e-46cf-9311-d4f7707096fb", + "id": "157", "metadata": {}, "source": [ "### Filtering\n", @@ -1767,7 +1767,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ecc4a718-1bd7-4381-a235-156b4464ab7b", + "id": "158", "metadata": {}, "outputs": [], "source": [ @@ -1776,7 +1776,7 @@ }, { "cell_type": "markdown", - "id": "e6e7cf74-4c56-48e1-88a8-135d35ed5b0f", + "id": "159", "metadata": {}, "source": [ "This returns a \"list\" of every row for which the criteria on the `mag` column is greater than `2`.\n", @@ -1786,7 +1786,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cd158403-9934-4a84-8088-12c2c834d032", + "id": "160", "metadata": {}, "outputs": [], "source": [ @@ -1795,7 +1795,7 @@ }, { "cell_type": "markdown", - "id": "6714accc-73de-4b0c-8cff-3012095d1f6c", + "id": "161", "metadata": {}, "source": [ "We can use masks with `loc`:" @@ -1804,7 +1804,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c1e1a7cc-4574-429f-a94d-e4f7ed7ef7bf", + "id": "162", "metadata": {}, "outputs": [], "source": [ @@ -1816,7 +1816,7 @@ }, { "cell_type": "markdown", - "id": "c7d58771-5648-4989-a348-9179e778287a", + "id": "163", "metadata": {}, "source": [ "Masks can be created using multiple criteria when combined with bitwise operators:\n", @@ -1829,7 +1829,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c1df0bd3-56f3-4a89-a906-04a9e3e06453", + "id": "164", "metadata": {}, "outputs": [], "source": [ @@ -1841,7 +1841,7 @@ }, { "cell_type": "markdown", - "id": "a3effd5b-7bae-429f-80b3-f8d0462f430f", + "id": "165", "metadata": {}, "source": [ "An example with an OR condition, which is less restrictive:" @@ -1850,7 +1850,7 @@ { "cell_type": "code", "execution_count": null, - "id": "179bcb59-3db5-4e9c-a607-38691ffac8c6", + "id": "166", "metadata": {}, "outputs": [], "source": [ @@ -1862,7 +1862,7 @@ }, { "cell_type": "markdown", - "id": "320dcc11-8006-46f3-ad6a-809ba81b8f40", + "id": "167", "metadata": {}, "source": [ "Masks can be created from any criteria that results in a Boolean. For example, we can select all earthquakes with the string `Alaska` in the `place` column with a non-null value for the `alert` column. To get non-nulls, we can use the `isnull()` method with the bitwise negation operator (`~`) or the `notnull()` method:" @@ -1871,7 +1871,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85291e70-6b84-490c-b891-8abd3ed10a8c", + "id": "168", "metadata": {}, "outputs": [], "source": [ @@ -1883,7 +1883,7 @@ }, { "cell_type": "markdown", - "id": "b0ccb828-83fe-477e-847b-5f6c47f42fea", + "id": "169", "metadata": {}, "source": [ "We can even use regular expressions here:" @@ -1892,7 +1892,7 @@ { "cell_type": "code", "execution_count": null, - "id": "09ac7f75-6d4d-46c1-a569-56bef4786939", + "id": "170", "metadata": {}, "outputs": [], "source": [ @@ -1904,7 +1904,7 @@ }, { "cell_type": "markdown", - "id": "b2091fbc-9e47-43f2-a2bb-f6112ed1c1dd", + "id": "171", "metadata": {}, "source": [ "We can use the `between()` method to turn 2 individual checks (is less than or equal to some maximum value and is greater than or equal to some minimum value) into a single one. Note this is inclusive of the endpoint by default:" @@ -1913,7 +1913,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a84a4803-4ac3-4655-ade8-9c78f21343f1", + "id": "172", "metadata": {}, "outputs": [], "source": [ @@ -1925,7 +1925,7 @@ }, { "cell_type": "markdown", - "id": "f885e6a9-4d63-4377-a4bd-4b9507119c23", + "id": "173", "metadata": {}, "source": [ "We can use the `isin()` method to check for membership in a list of values:" @@ -1934,7 +1934,7 @@ { "cell_type": "code", "execution_count": null, - "id": "af40e12a-cee7-48bc-a6d8-3ebfc32d55bb", + "id": "174", "metadata": {}, "outputs": [], "source": [ @@ -1946,7 +1946,7 @@ }, { "cell_type": "markdown", - "id": "e06920e1-9605-4e85-b1ff-d29464361dd4", + "id": "175", "metadata": {}, "source": [ "We can grab the index of the minimum and maximum values of a given column and use those to select the entire row where they occur:" @@ -1955,7 +1955,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d0601f82-8367-434f-847e-4165f771973f", + "id": "176", "metadata": {}, "outputs": [], "source": [ @@ -1965,7 +1965,7 @@ { "cell_type": "code", "execution_count": null, - "id": "875f10b5-6bd4-4120-be32-80a1d67e55f8", + "id": "177", "metadata": {}, "outputs": [], "source": [ @@ -1977,7 +1977,7 @@ }, { "cell_type": "markdown", - "id": "4a0d3de1-5cc0-43ae-9d90-b3a7d4efb828", + "id": "178", "metadata": {}, "source": [ "Note that there is a `filter()` method, but it doesn't filter the data in the same sense as we discussed in this section. Here are a few things you can do with this method.\n", @@ -1988,7 +1988,7 @@ { "cell_type": "code", "execution_count": null, - "id": "02cde297-9c88-4113-a098-89162b822eb5", + "id": "179", "metadata": {}, "outputs": [], "source": [ @@ -1997,7 +1997,7 @@ }, { "cell_type": "markdown", - "id": "e2b5d2c5-ba3e-484a-8953-3a85b55017ea", + "id": "180", "metadata": {}, "source": [ "- grab all the columns that contain a string with the `like` parameter:" @@ -2006,7 +2006,7 @@ { "cell_type": "code", "execution_count": null, - "id": "111a77b7-41fc-4222-9c6b-04b50c7a8437", + "id": "181", "metadata": {}, "outputs": [], "source": [ @@ -2015,7 +2015,7 @@ }, { "cell_type": "markdown", - "id": "d01a1a5e-9572-4ba1-b949-e5d520be01dd", + "id": "182", "metadata": {}, "source": [ "- use regular expressions; here, we select any columns that start with `t`:" @@ -2024,7 +2024,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3566826c-a839-4174-9a64-db8530f20f2c", + "id": "183", "metadata": {}, "outputs": [], "source": [ @@ -2033,7 +2033,7 @@ }, { "cell_type": "markdown", - "id": "3e16daf0-c816-43e9-8d97-39ff93f5547a", + "id": "184", "metadata": {}, "source": [ "- use `filter()` along the rows, by passing in `axis=0`. Here, we will use the `place` column as the index (we will cover `set_index()` in chapter 3):" @@ -2042,7 +2042,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0f6c4821-a6bb-4f41-bb75-a8201256edf3", + "id": "185", "metadata": {}, "outputs": [], "source": [ @@ -2051,7 +2051,7 @@ }, { "cell_type": "markdown", - "id": "9a810d3b-b36f-46df-8577-5479bd9372dd", + "id": "186", "metadata": {}, "source": [ "This also works on `Series` objects and will run on the index:" @@ -2060,7 +2060,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d8e556bf-9bf1-4602-9b64-a0ab98c61e16", + "id": "187", "metadata": {}, "outputs": [], "source": [ @@ -2069,7 +2069,7 @@ }, { "cell_type": "markdown", - "id": "24fcb785-5be6-484b-b225-cbf80a7de46b", + "id": "188", "metadata": {}, "source": [ "## Adding and removing data" @@ -2077,7 +2077,7 @@ }, { "cell_type": "markdown", - "id": "284ad335-eb03-41ad-9b1f-e5919a96c002", + "id": "189", "metadata": {}, "source": [ "### Adding new columns" @@ -2086,7 +2086,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1a9b8a23-43ec-4e32-a2f8-52e558966ae5", + "id": "190", "metadata": {}, "outputs": [], "source": [ @@ -2096,7 +2096,7 @@ }, { "cell_type": "markdown", - "id": "cc81ae20-acdb-4c24-8648-c9931d8bd116", + "id": "191", "metadata": {}, "source": [ "...or a Boolean mask:" @@ -2105,7 +2105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61585f20-c87a-4269-b41c-1e27ae00c0db", + "id": "192", "metadata": {}, "outputs": [], "source": [ @@ -2115,7 +2115,7 @@ }, { "cell_type": "markdown", - "id": "411da7dc-326a-4ec3-a94e-5b046a2f5ad4", + "id": "193", "metadata": {}, "source": [ "### Concatenation\n", @@ -2126,7 +2126,7 @@ { "cell_type": "code", "execution_count": null, - "id": "94bb10af-2644-41de-9466-bb37dffadbee", + "id": "194", "metadata": {}, "outputs": [], "source": [ @@ -2138,7 +2138,7 @@ }, { "cell_type": "markdown", - "id": "13a94fe7-6ef1-40b3-aa3f-0f6b32433b9f", + "id": "195", "metadata": {}, "source": [ "Concatenating along the row axis (`axis=0`) is equivalent to appending to the bottom.\n", @@ -2148,7 +2148,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2cafd8b7-61fa-44f1-8bcf-9f14d1a4b8d2", + "id": "196", "metadata": {}, "outputs": [], "source": [ @@ -2157,7 +2157,7 @@ }, { "cell_type": "markdown", - "id": "ba559768-6848-4eca-9b84-04b8b6e78417", + "id": "197", "metadata": {}, "source": [ "We have been working with a subset of the columns from the CSV file, but suppose that now we want to get some of the columns we ignored when we read in the data. Since we have added new columns in this notebook, we won't want to read in the file and perform those operations again. Instead, we will concatenate along the columns (`axis=1`) to add back what we are missing:" @@ -2166,7 +2166,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bc4b792d-a11b-4053-935b-d40b8d05ccba", + "id": "198", "metadata": {}, "outputs": [], "source": [ @@ -2178,7 +2178,7 @@ }, { "cell_type": "markdown", - "id": "b6b52a83-e7b3-44ca-95f5-06e33e638e6e", + "id": "199", "metadata": {}, "source": [ "Notice what happens if the index doesn't align though:" @@ -2187,7 +2187,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6057496e-bce1-44b6-908e-4ad8f16cdafe", + "id": "200", "metadata": {}, "outputs": [], "source": [ @@ -2199,7 +2199,7 @@ }, { "cell_type": "markdown", - "id": "0f4d7f31-24cd-4c0f-9c57-11e50f733686", + "id": "201", "metadata": {}, "source": [ "If the index doesn't align, we can align it before attempting the concatentation, which we will discuss in chapter 3.\n", @@ -2210,7 +2210,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b20707e8-befe-4de9-8e5f-190d7c1be8b6", + "id": "202", "metadata": {}, "outputs": [], "source": [ @@ -2221,7 +2221,7 @@ }, { "cell_type": "markdown", - "id": "36bcc323-264b-4f2d-9efb-96fb79711178", + "id": "203", "metadata": {}, "source": [ "In addition, we use `ignore_index`, since the index doesn't mean anything for us here. This gives us sequential values instead of what we had in the previous result:" @@ -2230,7 +2230,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e7ca6778-0d8a-4832-bf47-1e03e62c9655", + "id": "204", "metadata": {}, "outputs": [], "source": [ @@ -2241,7 +2241,7 @@ }, { "cell_type": "markdown", - "id": "d91e13ab-148f-4ab9-8902-2392d111fb73", + "id": "205", "metadata": {}, "source": [ "### Deleting data" @@ -2250,7 +2250,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8b8f87c6-e174-4821-bc32-f14d3a158752", + "id": "206", "metadata": {}, "outputs": [], "source": [ @@ -2260,7 +2260,7 @@ }, { "cell_type": "markdown", - "id": "925f1a97-6c20-47a7-a391-0cff6ad0971f", + "id": "207", "metadata": {}, "source": [ "If we don't know whether the column exists, we should use a `try`/`except` block:" @@ -2269,7 +2269,7 @@ { "cell_type": "code", "execution_count": null, - "id": "980766a2-e769-447c-8cc7-ee50f97152c3", + "id": "208", "metadata": {}, "outputs": [], "source": [ @@ -2282,7 +2282,7 @@ }, { "cell_type": "markdown", - "id": "e1b2c929-c04f-491b-8833-4f2ddcc60e18", + "id": "209", "metadata": {}, "source": [ "We can also use `pop()`. This will allow us to use the series we remove later. Note there will be an error if the key doesn't exist, so we can also use a `try`/`except` here:" @@ -2291,7 +2291,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f3a11ebe-9fa2-49ee-87d4-1acb2b412785", + "id": "210", "metadata": {}, "outputs": [], "source": [ @@ -2301,7 +2301,7 @@ }, { "cell_type": "markdown", - "id": "d20f86a3-e30f-4cd0-8eee-7cf7333eb9c8", + "id": "211", "metadata": {}, "source": [ "Notice we have a mask in `mag_negative` now:" @@ -2310,7 +2310,7 @@ { "cell_type": "code", "execution_count": null, - "id": "83a766d2-85ce-41ef-8d97-cb5a45908f29", + "id": "212", "metadata": {}, "outputs": [], "source": [ @@ -2319,7 +2319,7 @@ }, { "cell_type": "markdown", - "id": "f1f128e4-22b0-4548-a12d-62a0302d679f", + "id": "213", "metadata": {}, "source": [ "Now, we can use `mag_negative` to filter our data:" @@ -2328,7 +2328,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5c7df96b-40a5-48d0-be6d-5a21414377fe", + "id": "214", "metadata": {}, "outputs": [], "source": [ @@ -2337,7 +2337,7 @@ }, { "cell_type": "markdown", - "id": "9dd8c7bc-c92f-4521-a9d0-1c2cf67273cb", + "id": "215", "metadata": {}, "source": [ "##### Using the `drop()` method\n", @@ -2348,7 +2348,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5741cd27-d743-43fe-a7da-370102f16948", + "id": "216", "metadata": {}, "outputs": [], "source": [ @@ -2357,7 +2357,7 @@ }, { "cell_type": "markdown", - "id": "cf571579-2f12-4d77-a188-1d4608a19149", + "id": "217", "metadata": {}, "source": [ "The `drop()` method drops along the row axis by default. If we pass in a list of columns with the `columns` argument, we can delete columns:" @@ -2366,7 +2366,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e1908743-ae22-4c6e-957e-14d6fdca9167", + "id": "218", "metadata": {}, "outputs": [], "source": [ @@ -2379,7 +2379,7 @@ }, { "cell_type": "markdown", - "id": "a3091d64-01f7-48b8-948b-849182b04711", + "id": "219", "metadata": {}, "source": [ "We also have the option of using `axis=1`:" @@ -2388,7 +2388,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85663c95-4335-4f07-a1fe-9399f353990d", + "id": "220", "metadata": {}, "outputs": [], "source": [ @@ -2399,7 +2399,7 @@ }, { "cell_type": "markdown", - "id": "4ee3ce5f-48c1-4192-8235-755357e8cffb", + "id": "221", "metadata": {}, "source": [ "By default, `drop()`, along with the majority of `DataFrame` methods, will return a new `DataFrame` object. If we just want to change the one we are working with, we can pass `inplace=True`. This should be used with care:" @@ -2408,7 +2408,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74f172b8-4932-44db-9610-c642629605ff", + "id": "222", "metadata": {}, "outputs": [], "source": [ @@ -2418,7 +2418,7 @@ }, { "cell_type": "markdown", - "id": "f8a4b593-1f86-44bf-a4be-ee5a1aac6dd2", + "id": "223", "metadata": {}, "source": [ "## Exercises (1)\n", @@ -2429,7 +2429,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4ff35ff3-bb5c-4efd-851a-7d1109b7db8c", + "id": "224", "metadata": {}, "outputs": [], "source": [ @@ -2439,7 +2439,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fbd3b178-6bdb-4e38-ab58-1fb2ade52ea5", + "id": "225", "metadata": {}, "outputs": [], "source": [ @@ -2448,7 +2448,7 @@ }, { "cell_type": "markdown", - "id": "f512ba83-5da2-4c64-beaf-654457f9a57c", + "id": "226", "metadata": {}, "source": [ "1. Determine the 95th percentile for earthquake magnitudes in Japan, specifically using the mb magnitude scale.\n" @@ -2457,7 +2457,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75dff56a-7560-45bd-92d3-b230af34d4f8", + "id": "227", "metadata": {}, "outputs": [], "source": [ @@ -2469,7 +2469,7 @@ }, { "cell_type": "markdown", - "id": "88273cc0-5ab3-4120-a565-0f53becc3ae2", + "id": "228", "metadata": {}, "source": [ "2. Calculate the proportion of earthquakes in Indonesia that were accompanied by tsunamis.\n" @@ -2478,7 +2478,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a2789f85-9886-4b60-a447-82483d0b6557", + "id": "229", "metadata": {}, "outputs": [], "source": [ @@ -2490,7 +2490,7 @@ }, { "cell_type": "markdown", - "id": "24f58970-bfca-469f-a6d8-8155b2803f73", + "id": "230", "metadata": {}, "source": [ "# Data wrangling\n", @@ -2500,7 +2500,7 @@ }, { "cell_type": "markdown", - "id": "09b80a91-dc72-488e-bec1-ef7dd062d556", + "id": "231", "metadata": {}, "source": [ "\n", @@ -2513,7 +2513,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bfef51e8-3b30-4dad-a9c2-30b9501aa029", + "id": "232", "metadata": {}, "outputs": [], "source": [ @@ -2525,7 +2525,7 @@ }, { "cell_type": "markdown", - "id": "64b07308-e1eb-49c1-82a9-282fc93be204", + "id": "233", "metadata": {}, "source": [ "## Cleaning data" @@ -2533,7 +2533,7 @@ }, { "cell_type": "markdown", - "id": "95ae0f18-eac6-407a-89e1-7a3c603b8f2f", + "id": "234", "metadata": {}, "source": [ "### Renaming Columns\n", @@ -2543,7 +2543,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5a2c2e90-8d8d-453b-b5f6-e72b9c78a061", + "id": "235", "metadata": {}, "outputs": [], "source": [ @@ -2552,7 +2552,7 @@ }, { "cell_type": "markdown", - "id": "f31eb44d-4eb2-428c-9db3-36c989ef886a", + "id": "236", "metadata": {}, "source": [ "We want to rename the `value` column to indicate it contains the temperature in Celsius and the `attributes` column to say `flags` since each value in the comma-delimited string is a different flag about the data collection. For this task, we use the `rename()` method and pass in a dictionary mapping the column names to their new names. We pass `inplace=True` to change our original dataframe instead of getting a new one back:" @@ -2561,7 +2561,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6d622759-43bd-4f67-a056-62e9fd9480d2", + "id": "237", "metadata": {}, "outputs": [], "source": [ @@ -2575,7 +2575,7 @@ }, { "cell_type": "markdown", - "id": "35158c54-7f99-4d56-82f4-e64c7fcda999", + "id": "238", "metadata": {}, "source": [ "Those columns have been successfully renamed:" @@ -2584,7 +2584,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cac2bbc9-0952-4c2f-bd21-a64419090400", + "id": "239", "metadata": {}, "outputs": [], "source": [ @@ -2593,7 +2593,7 @@ }, { "cell_type": "markdown", - "id": "91daa6d0-6276-4479-87d8-741c347b6f98", + "id": "240", "metadata": {}, "source": [ "We can also perform string operations on the column names with `rename()`:" @@ -2602,7 +2602,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a4ed2238-9549-4b2f-b26c-9e6cccd881ef", + "id": "241", "metadata": {}, "outputs": [], "source": [ @@ -2611,7 +2611,7 @@ }, { "cell_type": "markdown", - "id": "afc6be31-f464-4ee7-924b-462e9cfa3c91", + "id": "242", "metadata": {}, "source": [ "### Type Conversion\n", @@ -2622,7 +2622,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dd3392ab-8a21-4abd-a390-8f75994d64bc", + "id": "243", "metadata": {}, "outputs": [], "source": [ @@ -2631,7 +2631,7 @@ }, { "cell_type": "markdown", - "id": "cb35d0f9-ebef-467e-a339-2a17cb3accfd", + "id": "244", "metadata": {}, "source": [ "Let's perform the conversion with `pd.to_datetime()`:" @@ -2640,7 +2640,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ed1d60de-33e7-4dce-b059-bf1b8d3299aa", + "id": "245", "metadata": {}, "outputs": [], "source": [ @@ -2650,7 +2650,7 @@ }, { "cell_type": "markdown", - "id": "bee4b0cb-5296-4bc5-9552-87f5aad4ecb0", + "id": "246", "metadata": {}, "source": [ "Now we get useful information when we use `describe()` on this column:" @@ -2659,7 +2659,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a5ee7776-4ac2-46c8-81e3-ae2ef9a534b5", + "id": "247", "metadata": {}, "outputs": [], "source": [ @@ -2668,7 +2668,7 @@ }, { "cell_type": "markdown", - "id": "3121a0e9-f7eb-4ff7-ba94-43a374d8f818", + "id": "248", "metadata": {}, "source": [ "We can use `tz_localize()` on a `DatetimeIndex` object to convert to a desired timezone:" @@ -2677,7 +2677,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d100dd8f-7f55-460d-8adb-5702cf3a55ce", + "id": "249", "metadata": {}, "outputs": [], "source": [ @@ -2686,7 +2686,7 @@ }, { "cell_type": "markdown", - "id": "39a1e396-4508-432e-a26e-b16bed806a08", + "id": "250", "metadata": {}, "source": [ "This also works with `Series`/`DataFrame` objects that have an index of type `DatetimeIndex`. Let's read in the CSV again for this example and set the `date` column to be the index and stored as a datetime:" @@ -2695,7 +2695,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34a6e2e9-a1b8-4eec-a17b-9c321810c227", + "id": "251", "metadata": {}, "outputs": [], "source": [ @@ -2708,7 +2708,7 @@ }, { "cell_type": "markdown", - "id": "2c4c73f9-2a89-488e-ada2-f0afe216d654", + "id": "252", "metadata": {}, "source": [ "We can use `tz_convert()` to convert to another timezone from there. If we convert the Eastern datetimes to UTC, they will now be at 5 AM, since `pandas` will use the offsets to convert:" @@ -2717,7 +2717,7 @@ { "cell_type": "code", "execution_count": null, - "id": "77431b6d-0cb4-4ace-ac4f-c8414a1195d8", + "id": "253", "metadata": {}, "outputs": [], "source": [ @@ -2726,7 +2726,7 @@ }, { "cell_type": "markdown", - "id": "8aedfd63-0e20-4f23-89b5-15ffbd605d38", + "id": "254", "metadata": {}, "source": [ "We can change the period of the index as well. We could change the period to be monthly to make it easier to aggregate later. (Aggregation will be discussed in chapter 4.)" @@ -2735,7 +2735,7 @@ { "cell_type": "code", "execution_count": null, - "id": "58cc19a4-a75e-41c9-9f6c-862e64836c04", + "id": "255", "metadata": {}, "outputs": [], "source": [ @@ -2744,7 +2744,7 @@ }, { "cell_type": "markdown", - "id": "a5e778b8-71ad-46e5-a23f-68e3033458eb", + "id": "256", "metadata": {}, "source": [ "We now get a `PeriodIndex` object, which we can change back into a `DatetimeIndex` object with `to_timestamp()`:" @@ -2753,7 +2753,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d988b5b1-0bbe-47ea-9fc6-ba079ec26f9a", + "id": "257", "metadata": {}, "outputs": [], "source": [ @@ -2762,7 +2762,7 @@ }, { "cell_type": "markdown", - "id": "ba436b81-ea51-4e67-a329-2d929cc90d9c", + "id": "258", "metadata": {}, "source": [ "We can use the `assign()` method for working with multiple columns at once (or creating new ones). Since our `date` column has already been converted, we need to read in the data again:" @@ -2771,7 +2771,7 @@ { "cell_type": "code", "execution_count": null, - "id": "120dee8a-745a-495b-abf9-197626b472a6", + "id": "259", "metadata": {}, "outputs": [], "source": [ @@ -2792,7 +2792,7 @@ }, { "cell_type": "markdown", - "id": "96f2bbc5-fd56-42ef-8ae8-04920a6a0e0e", + "id": "260", "metadata": {}, "source": [ "The `date` column now has datetimes and the `temp_F` column was added:" @@ -2801,7 +2801,7 @@ { "cell_type": "code", "execution_count": null, - "id": "951eb51f-7602-45df-ba72-430bc86f9fc3", + "id": "261", "metadata": {}, "outputs": [], "source": [ @@ -2810,7 +2810,7 @@ }, { "cell_type": "markdown", - "id": "510f2ce9-400d-4c72-9470-e96aa1ded692", + "id": "262", "metadata": {}, "source": [ "We can also use `astype()` to perform conversions. Let's create columns of the integer portion of the temperatures in Celsius and Fahrenheit. We will use **lambda functions** (first introduced in *Chapter 2, Working with Pandas DataFrames*), so that we can use the values being created in the `temp_F` column to calculate the `temp_F_whole` column. It is very common (and useful) to use lambda functions with `assign()`:" @@ -2819,7 +2819,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17707308-b978-4697-b14f-7234fd47ac66", + "id": "263", "metadata": {}, "outputs": [], "source": [ @@ -2835,7 +2835,7 @@ }, { "cell_type": "markdown", - "id": "2d257826-8501-4c8d-bc32-33d68255631e", + "id": "264", "metadata": {}, "source": [ "Creating categories:" @@ -2844,7 +2844,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5efc6bfe-2979-48d5-aa34-1dc0117e01c4", + "id": "265", "metadata": {}, "outputs": [], "source": [ @@ -2858,7 +2858,7 @@ { "cell_type": "code", "execution_count": null, - "id": "714fea0a-6ed2-45ba-b5da-201e0f000191", + "id": "266", "metadata": {}, "outputs": [], "source": [ @@ -2867,7 +2867,7 @@ }, { "cell_type": "markdown", - "id": "c9862fa0-f079-4ef9-bbf5-d1a07d4519fe", + "id": "267", "metadata": {}, "source": [ "Our categories have no order, but this is something that `pandas` supports:" @@ -2876,7 +2876,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3c50973d-85cc-4a26-bed8-b1c045645665", + "id": "268", "metadata": {}, "outputs": [], "source": [ @@ -2889,7 +2889,7 @@ }, { "cell_type": "markdown", - "id": "a769db10-8dc0-4ea1-b5df-1a44dbaf0ca0", + "id": "269", "metadata": {}, "source": [ "### Reordering, reindexing, and sorting\n", @@ -2899,7 +2899,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c5ff90e5-2823-4125-83c6-9a23b2148033", + "id": "270", "metadata": {}, "outputs": [], "source": [ @@ -2908,7 +2908,7 @@ }, { "cell_type": "markdown", - "id": "1bfe4a3b-f225-4d0c-9025-d6038de09aa8", + "id": "271", "metadata": {}, "source": [ "However, this isn't perfect because we have some ties, and they aren't sorted consistently.\n", @@ -2920,7 +2920,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9b9d59fb-31d2-4a0b-9ae3-ce6958ee3624", + "id": "272", "metadata": {}, "outputs": [], "source": [ @@ -2929,7 +2929,7 @@ }, { "cell_type": "markdown", - "id": "242d561d-b0db-4bf4-a99c-7fbcef6b7b19", + "id": "273", "metadata": {}, "source": [ "Notice that the index was jumbled in the past 2 results. Here, our index only stores the row number in the original data, but we may not need to keep track of that information. In this case, we can pass in `ignore_index=True` to get a new index after sorting:" @@ -2938,7 +2938,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b5a9724d-15b3-45a2-b3f4-5436d147ec3d", + "id": "274", "metadata": {}, "outputs": [], "source": [ @@ -2947,7 +2947,7 @@ }, { "cell_type": "markdown", - "id": "a162852d-d34c-45c6-bbea-01b5ffa5d848", + "id": "275", "metadata": {}, "source": [ "When just looking for the n-largest values, rather than wanting to sort all the data, we can use `nlargest()`:" @@ -2956,7 +2956,7 @@ { "cell_type": "code", "execution_count": null, - "id": "099d88c1-7905-4aea-ac31-cdb1ded2326e", + "id": "276", "metadata": {}, "outputs": [], "source": [ @@ -2965,7 +2965,7 @@ }, { "cell_type": "markdown", - "id": "cbbb64e7-2e16-4b40-8b00-0929327167da", + "id": "277", "metadata": {}, "source": [ "We use `nsmallest()` for the n-smallest values." @@ -2974,7 +2974,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4dcc977b-958d-49b3-abf6-24022112fb73", + "id": "278", "metadata": {}, "outputs": [], "source": [ @@ -2983,7 +2983,7 @@ }, { "cell_type": "markdown", - "id": "debebeac-5cda-4998-b899-ea35acd42f25", + "id": "279", "metadata": {}, "source": [ "The `sample()` method will give us rows (or columns with `axis=1`) at random.\n", @@ -2994,7 +2994,7 @@ { "cell_type": "code", "execution_count": null, - "id": "65ce441e-ef85-43c0-a3ae-3b581a45e53b", + "id": "280", "metadata": {}, "outputs": [], "source": [ @@ -3003,7 +3003,7 @@ }, { "cell_type": "markdown", - "id": "fc3cef57-eaa2-4659-bab6-dd53960d2664", + "id": "281", "metadata": {}, "source": [ "We can use `sort_index()` to order it again:" @@ -3012,7 +3012,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0935ee7f-38bf-44f7-9f09-e263d98e1d60", + "id": "282", "metadata": {}, "outputs": [], "source": [ @@ -3021,7 +3021,7 @@ }, { "cell_type": "markdown", - "id": "327b3dc7-b149-4a70-87e5-204016e18d0f", + "id": "283", "metadata": {}, "source": [ "The `sort_index()` method can also sort columns alphabetically:" @@ -3030,7 +3030,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33b2fab6-ad8e-4f97-b3cf-4e699b0bb94d", + "id": "284", "metadata": {}, "outputs": [], "source": [ @@ -3039,7 +3039,7 @@ }, { "cell_type": "markdown", - "id": "04be54e5-eec9-4d28-b475-a0e26287e1ca", + "id": "285", "metadata": {}, "source": [ "This can make selection with `loc` easier for many columns:" @@ -3048,7 +3048,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0b85341d-0cb8-4eaf-b09a-3a92e74f8ab1", + "id": "286", "metadata": {}, "outputs": [], "source": [ @@ -3057,7 +3057,7 @@ }, { "cell_type": "markdown", - "id": "80dce355-db3b-4fc9-a230-4e5d26fbd7cf", + "id": "287", "metadata": {}, "source": [ "We must sort the index to compare two dataframes. If the index is different, but the data is the same, they will be marked not-equal:" @@ -3066,7 +3066,7 @@ { "cell_type": "code", "execution_count": null, - "id": "01f50d76-4980-4f8b-baf4-4d0a02fd7108", + "id": "288", "metadata": {}, "outputs": [], "source": [ @@ -3075,7 +3075,7 @@ }, { "cell_type": "markdown", - "id": "1f67c0d6-ac4e-40fd-9757-d692379215dc", + "id": "289", "metadata": {}, "source": [ "Sorting the index solves this issue:" @@ -3084,7 +3084,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33ee9a7a-3659-4632-a185-b8c104d1e6dc", + "id": "290", "metadata": {}, "outputs": [], "source": [ @@ -3093,7 +3093,7 @@ }, { "cell_type": "markdown", - "id": "599e9a7c-de20-438a-87ad-d059812ae028", + "id": "291", "metadata": {}, "source": [ "Let's set the `date` column as our index:" @@ -3102,7 +3102,7 @@ { "cell_type": "code", "execution_count": null, - "id": "57da63da-4265-42ac-9e99-3076c11c0031", + "id": "292", "metadata": {}, "outputs": [], "source": [ @@ -3112,7 +3112,7 @@ }, { "cell_type": "markdown", - "id": "f8d1a849-371d-450a-bd08-3c2960904f1d", + "id": "293", "metadata": {}, "source": [ "Now that we have an index of type `DatetimeIndex`, we can do datetime slicing and indexing.\n", @@ -3125,7 +3125,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0646c150-1cbf-4884-93e7-b3294e0361a0", + "id": "294", "metadata": {}, "outputs": [], "source": [ @@ -3134,7 +3134,7 @@ }, { "cell_type": "markdown", - "id": "0c7bebf9-ce19-4641-98c7-691a9aafb09c", + "id": "295", "metadata": {}, "source": [ "We can also use `reset_index()` to get a fresh index and move our current index into a column for safe keeping. This is especially useful if we had data, such as the date, in the index that we don't want to lose:" @@ -3143,7 +3143,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b336eeab-efa7-4a90-9dc8-2ad66a5e7eb2", + "id": "296", "metadata": {}, "outputs": [], "source": [ @@ -3152,7 +3152,7 @@ }, { "cell_type": "markdown", - "id": "28e13880-7f8f-4f48-89c0-e6c373ce5dbb", + "id": "297", "metadata": {}, "source": [ "Reindexing allows us to conform our axis to contain a given set of labels.\n", @@ -3164,7 +3164,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2a484d50-7dc9-4f28-b7af-c39628214e45", + "id": "298", "metadata": {}, "outputs": [], "source": [ @@ -3179,7 +3179,7 @@ }, { "cell_type": "markdown", - "id": "ec6a21af-6bf6-458d-b91c-f78f6eda176a", + "id": "299", "metadata": {}, "source": [ "If we want to look at the value of a portfolio (group of assets) that trade on different days, we need to handle the mismatch in the index.\n", @@ -3190,7 +3190,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c9df1ef1-e62e-474d-8166-7a807fbcf01e", + "id": "300", "metadata": {}, "outputs": [], "source": [ @@ -3208,7 +3208,7 @@ }, { "cell_type": "markdown", - "id": "684747ec-6942-4469-af19-ed52b65ebbfb", + "id": "301", "metadata": {}, "source": [ "It may not be immediately obvious what is wrong with the previous data, but with a visualization we can easily see the cyclical pattern of drops on the days the stock market is closed.\n", @@ -3219,7 +3219,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c109d719-e510-4588-9c7a-09049bb8d9f6", + "id": "302", "metadata": {}, "outputs": [], "source": [ @@ -3229,7 +3229,7 @@ }, { "cell_type": "markdown", - "id": "f894c86e-480f-4977-aa8a-194d808a42a1", + "id": "303", "metadata": {}, "source": [ "Now we can see why we need to reindex:" @@ -3238,7 +3238,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8d5c47b6-2f4d-419f-a78f-3c443a82c4ad", + "id": "304", "metadata": {}, "outputs": [], "source": [ @@ -3260,7 +3260,7 @@ }, { "cell_type": "markdown", - "id": "ffc54d4e-0e6a-4c56-8d14-ead611db8468", + "id": "305", "metadata": {}, "source": [ "We need to align the index of the S&P 500 to match bitcoin in order to fix this.\n", @@ -3270,7 +3270,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9dc446dc-d248-44d7-82c0-5e2c95239a2d", + "id": "306", "metadata": {}, "outputs": [], "source": [ @@ -3281,7 +3281,7 @@ }, { "cell_type": "markdown", - "id": "3a772cea-d1af-4311-8108-624af2dca7b9", + "id": "307", "metadata": {}, "source": [ "So now we have rows for every day of the year, but all the weekends and holidays have `NaN` values.\n", @@ -3292,7 +3292,7 @@ { "cell_type": "code", "execution_count": null, - "id": "55b5d77a-bede-4f0f-8fd8-7eba1b6986b8", + "id": "308", "metadata": {}, "outputs": [], "source": [ @@ -3302,7 +3302,7 @@ }, { "cell_type": "markdown", - "id": "f82b419b-f7c1-47dc-8722-366eab18093e", + "id": "309", "metadata": {}, "source": [ "To isolate the changes happening with the forward-filling, we can use the `compare()` method.\n", @@ -3314,7 +3314,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0483f7c0-800a-4f5d-b696-2a1c6b15d505", + "id": "310", "metadata": {}, "outputs": [], "source": [ @@ -3325,7 +3325,7 @@ }, { "cell_type": "markdown", - "id": "9df1ebcc-c63b-4dc6-ac4f-3a9d0bb8ca31", + "id": "311", "metadata": {}, "source": [ "This isn't perfect though.\n", @@ -3335,7 +3335,7 @@ { "cell_type": "code", "execution_count": null, - "id": "495aed9b-c7a8-4a37-af57-886528e55adb", + "id": "312", "metadata": {}, "outputs": [], "source": [ @@ -3357,7 +3357,7 @@ }, { "cell_type": "markdown", - "id": "c5fcb8b9-9cf2-4d25-b4b0-0d7a5fccbf7d", + "id": "313", "metadata": {}, "source": [ "If we create a visualization comparing the reindexed data to the first attempt, we see how reindexing helped maintain the asset value when the market was closed:" @@ -3366,7 +3366,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cecef783-032c-4c52-9e27-0777caddda38", + "id": "314", "metadata": {}, "outputs": [], "source": [ @@ -3396,7 +3396,7 @@ }, { "cell_type": "markdown", - "id": "620b660c-62f0-4c6a-8849-7486f8792bf0", + "id": "315", "metadata": {}, "source": [ "## Reshaping data\n", @@ -3407,7 +3407,7 @@ { "cell_type": "code", "execution_count": null, - "id": "362ab9f2-f412-4a77-b754-0bcc9dbd3019", + "id": "316", "metadata": {}, "outputs": [], "source": [ @@ -3427,7 +3427,7 @@ }, { "cell_type": "markdown", - "id": "f7b61af4-b991-487e-ab21-f219ddfbaff5", + "id": "317", "metadata": {}, "source": [ "### Transposing\n", @@ -3437,7 +3437,7 @@ { "cell_type": "code", "execution_count": null, - "id": "95e9899b-412d-45d3-b025-f5e9bdcd3399", + "id": "318", "metadata": {}, "outputs": [], "source": [ @@ -3446,7 +3446,7 @@ }, { "cell_type": "markdown", - "id": "4c97e234-1058-453c-a7f3-79aae2380529", + "id": "319", "metadata": {}, "source": [ "### Pivoting\n", @@ -3459,7 +3459,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2a5283f3-4dc6-4ab3-b2fb-aea12c52b3c2", + "id": "320", "metadata": {}, "outputs": [], "source": [ @@ -3471,7 +3471,7 @@ }, { "cell_type": "markdown", - "id": "d898be7e-fd5a-4142-9455-5e8f0e1b2799", + "id": "321", "metadata": {}, "source": [ "Now that the data is pivoted, we have wide format data that we can grab summary statistics with:" @@ -3480,7 +3480,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fcb68d6f-a352-4d6a-a76f-64733e7b9865", + "id": "322", "metadata": {}, "outputs": [], "source": [ @@ -3489,7 +3489,7 @@ }, { "cell_type": "markdown", - "id": "be9753cf-e36a-41cf-aec8-f8f5ec957c21", + "id": "323", "metadata": {}, "source": [ "We can also provide multiple values to pivot on, which will result in a hierarchical index:" @@ -3498,7 +3498,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c5a8b54f-f2b1-4369-9f4a-67a6771457c8", + "id": "324", "metadata": {}, "outputs": [], "source": [ @@ -3510,7 +3510,7 @@ }, { "cell_type": "markdown", - "id": "528a041f-974b-41cb-9d80-c4314c770982", + "id": "325", "metadata": {}, "source": [ "With the hierarchical index, if we want to select `TMIN` in Fahrenheit, we will first need to select `temp_F` and then `TMIN`:" @@ -3519,7 +3519,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e2ecd493-0166-4e4e-8369-9e6f4f2c70a8", + "id": "326", "metadata": {}, "outputs": [], "source": [ @@ -3528,7 +3528,7 @@ }, { "cell_type": "markdown", - "id": "1079eb6d-8072-44dc-9217-718a9d048c5a", + "id": "327", "metadata": {}, "source": [ "#### `unstack()`\n", @@ -3540,7 +3540,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ed08bd8b-320d-4a4c-9a6d-715d5e2419be", + "id": "328", "metadata": {}, "outputs": [], "source": [ @@ -3550,7 +3550,7 @@ }, { "cell_type": "markdown", - "id": "649749f2-6e59-44d0-aad1-ed9b63c62fa6", + "id": "329", "metadata": {}, "source": [ "Notice there are now 2 index sections of the dataframe:" @@ -3559,7 +3559,7 @@ { "cell_type": "code", "execution_count": null, - "id": "117f9618-8d91-4407-a3c0-eba944c5846e", + "id": "330", "metadata": {}, "outputs": [], "source": [ @@ -3568,7 +3568,7 @@ }, { "cell_type": "markdown", - "id": "378d7381-6749-4150-80f4-588eeb769631", + "id": "331", "metadata": {}, "source": [ "With an index of type `MultiIndex`, we can no longer use `pivot()`. We must now use `unstack()`, which by default moves the innermost index onto the columns:" @@ -3577,7 +3577,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53486df3-4989-46f1-8365-4006298e70c1", + "id": "332", "metadata": {}, "outputs": [], "source": [ @@ -3587,7 +3587,7 @@ }, { "cell_type": "markdown", - "id": "bc4f41b8-de42-4f6d-b3a0-ffd8661f4a6a", + "id": "333", "metadata": {}, "source": [ "The `unstack()` method also provides the `fill_value` parameter, which let's us fill-in any `NaN` values that might arise from this restructuring of the data. Consider the case that we have data for the average temperature on October 1, 2018, but no other date:" @@ -3596,7 +3596,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aa107955-3e56-42e5-8ccc-b018ecc27a01", + "id": "334", "metadata": {}, "outputs": [], "source": [ @@ -3614,7 +3614,7 @@ }, { "cell_type": "markdown", - "id": "1ecd3474-1b65-4bc6-b220-a02663359452", + "id": "335", "metadata": {}, "source": [ "If we use `unstack()` in this case, we will have `NaN` for the `TAVG` columns every day but October 1, 2018:" @@ -3623,7 +3623,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c84d0039-12ca-436a-80c3-e6056a266411", + "id": "336", "metadata": {}, "outputs": [], "source": [ @@ -3632,7 +3632,7 @@ }, { "cell_type": "markdown", - "id": "e67ed896-e05c-4dad-9d62-ae740bef41b1", + "id": "337", "metadata": {}, "source": [ "To address this, we can pass in an appropriate `fill_value`. However, we are restricted to passing in a value for this, not a strategy (like we saw with `fillna()`), so while `-40` is definitely not be the best value, we can use it to illustrate how this works, since this is the temperature at which Fahrenheit and Celsius are equal:" @@ -3641,7 +3641,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cc7eedf8-cd2b-4977-a89f-dd11a19e3b1b", + "id": "338", "metadata": {}, "outputs": [], "source": [ @@ -3650,7 +3650,7 @@ }, { "cell_type": "markdown", - "id": "c91a5d0b-7f67-4321-8d8b-f32d251a89b7", + "id": "339", "metadata": {}, "source": [ "### Melting\n", @@ -3661,7 +3661,7 @@ { "cell_type": "code", "execution_count": null, - "id": "444bd843-48b9-49f9-be5f-deb408e922fa", + "id": "340", "metadata": {}, "outputs": [], "source": [ @@ -3671,7 +3671,7 @@ }, { "cell_type": "markdown", - "id": "3364a0ed-3963-4a77-8660-ddb1039b4cdd", + "id": "341", "metadata": {}, "source": [ "#### `melt()`\n", @@ -3687,7 +3687,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7e98c5d0-6237-4a1a-bf67-a40dca1df4c9", + "id": "342", "metadata": {}, "outputs": [], "source": [ @@ -3702,7 +3702,7 @@ }, { "cell_type": "markdown", - "id": "f23d61fd-7f56-4818-a62b-8f9f3d57b335", + "id": "343", "metadata": {}, "source": [ "#### `stack()`\n", @@ -3712,7 +3712,7 @@ { "cell_type": "code", "execution_count": null, - "id": "919d019b-4834-4eed-a7ed-642634a3acd1", + "id": "344", "metadata": {}, "outputs": [], "source": [ @@ -3722,7 +3722,7 @@ }, { "cell_type": "markdown", - "id": "31cac1a3-e976-4445-ac66-d50bcb5ca208", + "id": "345", "metadata": {}, "source": [ "By running `stack()` now, we will create a second level in our index which will contain the column names of our dataframe (`TMAX`, `TMIN`, `TOBS`). This will leave us with a `Series` object containing the values:" @@ -3731,7 +3731,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e0d2f431-13a2-46ca-9d63-2b5c53397dfd", + "id": "346", "metadata": {}, "outputs": [], "source": [ @@ -3741,7 +3741,7 @@ }, { "cell_type": "markdown", - "id": "8a9717f1-8ab5-42e0-a58b-c4a53b4ef497", + "id": "347", "metadata": {}, "source": [ "We can use the `to_frame()` method on our `Series` object to turn it into a `DataFrame` object. Since the series doesn't have a name at the moment, we will pass in the name as an argument:" @@ -3750,7 +3750,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2ec55ed4-775a-4dce-86cf-61e977514e00", + "id": "348", "metadata": {}, "outputs": [], "source": [ @@ -3760,7 +3760,7 @@ }, { "cell_type": "markdown", - "id": "53a4a090-ef86-4dd3-899d-4f1ae04c6a24", + "id": "349", "metadata": {}, "source": [ "Once again, we have an index of type `MultiIndex`:" @@ -3769,7 +3769,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9290310d-a5c4-4e0c-bcfe-512dcef830b3", + "id": "350", "metadata": {}, "outputs": [], "source": [ @@ -3778,7 +3778,7 @@ }, { "cell_type": "markdown", - "id": "6e8c172a-25c6-4e19-9428-519e002fb3e1", + "id": "351", "metadata": {}, "source": [ "Unfortunately, we don't have a name for the `datatype` level:" @@ -3787,7 +3787,7 @@ { "cell_type": "code", "execution_count": null, - "id": "eebd0d9b-4dcb-4ac7-9d14-1961ef77780a", + "id": "352", "metadata": {}, "outputs": [], "source": [ @@ -3796,7 +3796,7 @@ }, { "cell_type": "markdown", - "id": "563ded23-a9d9-4844-b094-2c197c7151d4", + "id": "353", "metadata": {}, "source": [ "We can use `set_names()` to address this though:" @@ -3805,7 +3805,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fcd36c28-eeca-4489-ba53-59c413648c56", + "id": "354", "metadata": {}, "outputs": [], "source": [ @@ -3815,7 +3815,7 @@ }, { "cell_type": "markdown", - "id": "50005b2d-bb2f-4149-9029-9907ad543b97", + "id": "355", "metadata": {}, "source": [ "## Exercises (2)\n", @@ -3825,7 +3825,7 @@ }, { "cell_type": "markdown", - "id": "7c4a5330-cba6-4086-980c-ede1b781d36d", + "id": "356", "metadata": {}, "source": [ "**Exercise 1**\n", @@ -3839,7 +3839,7 @@ }, { "cell_type": "markdown", - "id": "b83e128f-058e-4584-a49e-b1bbd41e7386", + "id": "357", "metadata": {}, "source": [ "**Exercise 2**\n", @@ -3850,7 +3850,7 @@ }, { "cell_type": "markdown", - "id": "e685d982-03ef-4ac3-b301-358e91f4b225", + "id": "358", "metadata": {}, "source": [ "**Exercise 3**\n", @@ -3860,7 +3860,7 @@ }, { "cell_type": "markdown", - "id": "fae89cbd-0b6d-4e26-ab74-39113f9c7a3b", + "id": "359", "metadata": {}, "source": [ "# Data aggregation" @@ -3868,7 +3868,7 @@ }, { "cell_type": "markdown", - "id": "3c4e5ba0-60da-4028-b195-f50773349fcb", + "id": "360", "metadata": {}, "source": [ "We are going to use some daily weather data of New York City in 2018 collected from the [National Centers for Environmental Information (NCEI) API](https://www.ncdc.noaa.gov/cdo-web/webservices/v2)." @@ -3877,7 +3877,7 @@ { "cell_type": "code", "execution_count": null, - "id": "566e7653-2f7e-4615-bb51-e0d22bba2f63", + "id": "361", "metadata": {}, "outputs": [], "source": [ @@ -3889,7 +3889,7 @@ }, { "cell_type": "markdown", - "id": "e7c79e71-673a-4c66-b2d5-b417edfa6991", + "id": "362", "metadata": {}, "source": [ "### Querying" @@ -3897,7 +3897,7 @@ }, { "cell_type": "markdown", - "id": "12bd6ff6-f6e7-4ae7-aba9-4bcd69b07a58", + "id": "363", "metadata": {}, "source": [ "The `query()` method filters a `DataFrame` based on some criteria.\n", @@ -3907,7 +3907,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2761f4c4-db73-4d3a-a1ba-73d6d80d2fb2", + "id": "364", "metadata": {}, "outputs": [], "source": [ @@ -3917,7 +3917,7 @@ }, { "cell_type": "markdown", - "id": "f0b75ead-eeef-4004-8314-921302c58b4a", + "id": "365", "metadata": {}, "source": [ "This can be equivalently performed with a SQL query on the `weather.db` database file, if you're familiar with it:\n", @@ -3932,7 +3932,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6e7d5337-f7b7-413b-b1a2-e0377eac7097", + "id": "366", "metadata": {}, "outputs": [], "source": [ @@ -3949,7 +3949,7 @@ }, { "cell_type": "markdown", - "id": "970c99de-926a-4166-8be1-7968865f03ba", + "id": "367", "metadata": {}, "source": [ "Note this is also equivalent to creating Boolean masks:" @@ -3958,7 +3958,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41fba2f4-c1e0-4b36-b4ad-0f985e39b5ff", + "id": "368", "metadata": {}, "outputs": [], "source": [ @@ -3971,7 +3971,7 @@ }, { "cell_type": "markdown", - "id": "a79017a0-910b-4e5e-a163-b91bc04b4354", + "id": "369", "metadata": {}, "source": [ "### Merging" @@ -3979,7 +3979,7 @@ }, { "cell_type": "markdown", - "id": "a0c75cde-064a-4283-9302-af7802007e65", + "id": "370", "metadata": {}, "source": [ "We have data for many different stations each day; however, we don't know what the stations are, just their IDs.\n", @@ -3989,7 +3989,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4d1b69f9-66d1-4d4a-b9ea-e82eaa2b4c44", + "id": "371", "metadata": {}, "outputs": [], "source": [ @@ -3999,7 +3999,7 @@ }, { "cell_type": "markdown", - "id": "50df68ed-8031-4f25-963d-6d478c186d60", + "id": "372", "metadata": {}, "source": [ "And here's our `weather` dataset again:" @@ -4008,7 +4008,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8436e846-a58d-4edd-ba9e-a25fff86c494", + "id": "373", "metadata": {}, "outputs": [], "source": [ @@ -4017,7 +4017,7 @@ }, { "cell_type": "markdown", - "id": "318a8c7b-4813-4e26-b075-00d5df4bbda3", + "id": "374", "metadata": {}, "source": [ "We can join our data by matching up the `station_info.id` column with the `weather.station` column.\n", @@ -4027,7 +4027,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1ad802db-9bbf-40d3-96fb-a830d0d8e17d", + "id": "375", "metadata": {}, "outputs": [], "source": [ @@ -4036,7 +4036,7 @@ }, { "cell_type": "markdown", - "id": "1c0f8cfd-7279-468b-85d3-0739bbcb861d", + "id": "376", "metadata": {}, "source": [ "While `station_info` has one row per station, the `weather` dataframe has many entries per station.\n", @@ -4046,7 +4046,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48f58d57-f5b8-40e6-83b8-b68160a2ce88", + "id": "377", "metadata": {}, "outputs": [], "source": [ @@ -4055,7 +4055,7 @@ }, { "cell_type": "markdown", - "id": "deee4719-44be-473d-aaf5-d3027cfa5217", + "id": "378", "metadata": {}, "source": [ "When working with joins, it is important to keep an eye on the row count. Some join types will lead to data loss. Remember that we can get this with `shape`:" @@ -4064,7 +4064,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dcb49f48-285b-4cc7-975c-1a6d20c21685", + "id": "379", "metadata": {}, "outputs": [], "source": [ @@ -4073,7 +4073,7 @@ }, { "cell_type": "markdown", - "id": "a7050a06-6a36-4065-af85-d4b8c233a18d", + "id": "380", "metadata": {}, "source": [ "Since we will be doing this often, it makes more sense to write a function:" @@ -4082,7 +4082,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e2764b5a-d09b-45bc-89b7-d70e6d43f65a", + "id": "381", "metadata": {}, "outputs": [], "source": [ @@ -4094,7 +4094,7 @@ }, { "cell_type": "markdown", - "id": "1ec53e29-69a2-48fb-9d4f-4889bee8bf12", + "id": "382", "metadata": {}, "source": [ "By default, `merge()` performs an inner join.\n", @@ -4105,7 +4105,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28ae155b-9cdc-403a-86a7-72c131839750", + "id": "383", "metadata": {}, "outputs": [], "source": [ @@ -4115,7 +4115,7 @@ }, { "cell_type": "markdown", - "id": "379dd910-858f-4534-bdb9-38c8f09da072", + "id": "384", "metadata": {}, "source": [ "We can remove the duplication of information in the `station` and `id` columns by renaming one of them before the merge and then simply using `on`:" @@ -4124,7 +4124,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14aa6056-4662-4a82-96c1-7e2964cd9f40", + "id": "385", "metadata": {}, "outputs": [], "source": [ @@ -4133,7 +4133,7 @@ }, { "cell_type": "markdown", - "id": "801b8eda-4cb9-4d14-b065-f4edfe7196cd", + "id": "386", "metadata": {}, "source": [ "We are losing stations that don't have weather observations associated with them, if we don't want to lose these rows, we perform a right or left join instead of the inner join:" @@ -4142,7 +4142,7 @@ { "cell_type": "code", "execution_count": null, - "id": "728c9c25-464e-48bc-b58e-67997ea2b392", + "id": "387", "metadata": {}, "outputs": [], "source": [ @@ -4154,7 +4154,7 @@ }, { "cell_type": "markdown", - "id": "028bc957-4ebb-4ea1-b3a3-2453737d1221", + "id": "388", "metadata": {}, "source": [ "The left and right join as we performed above are equivalent because the side for which we kept the rows without matches was the same in both cases:" @@ -4163,7 +4163,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6f485fc2-1371-40e2-8ad4-4b7557d3e04c", + "id": "389", "metadata": {}, "outputs": [], "source": [ @@ -4174,7 +4174,7 @@ }, { "cell_type": "markdown", - "id": "52fbc802-f1db-447d-84d9-ba6ce3b1ec19", + "id": "390", "metadata": {}, "source": [ "Note we have additional rows in the left and right joins because we kept all the stations that didn't have weather observations:" @@ -4183,7 +4183,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2b509bf7-e4fc-416e-baed-d6fa3052688d", + "id": "391", "metadata": {}, "outputs": [], "source": [ @@ -4192,7 +4192,7 @@ }, { "cell_type": "markdown", - "id": "7ebba9c2-1126-4c80-8f24-55aa69f8405e", + "id": "392", "metadata": {}, "source": [ "If we query the station information for stations that have `US1NY` in their ID and perform an outer join, we can see where the mismatches occur:" @@ -4201,7 +4201,7 @@ { "cell_type": "code", "execution_count": null, - "id": "99afd11c-b934-48ef-8b50-f48086b7224b", + "id": "393", "metadata": {}, "outputs": [], "source": [ @@ -4218,7 +4218,7 @@ }, { "cell_type": "markdown", - "id": "ebea69d4-be4c-4109-bcb9-1c8b84184dd9", + "id": "394", "metadata": {}, "source": [ "## `DataFrame` operations\n", @@ -4232,7 +4232,7 @@ { "cell_type": "code", "execution_count": null, - "id": "930668c3-6a83-4b23-bee5-e8868810e60b", + "id": "395", "metadata": {}, "outputs": [], "source": [ @@ -4246,7 +4246,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d267057c-c222-47ef-b06d-10b4dee359e8", + "id": "396", "metadata": {}, "outputs": [], "source": [ @@ -4256,7 +4256,7 @@ }, { "cell_type": "markdown", - "id": "0d94ab65-28f6-4236-a792-0f629bc18d0a", + "id": "397", "metadata": {}, "source": [ "### Arithmetics and statistics\n", @@ -4271,7 +4271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6e337804-07d4-4bac-a556-a826a57c29a4", + "id": "398", "metadata": {}, "outputs": [], "source": [ @@ -4283,7 +4283,7 @@ }, { "cell_type": "markdown", - "id": "88ab0277-b254-4867-95a4-28f15aab1bfd", + "id": "399", "metadata": {}, "source": [ "We can use `rank()` and `pct_change()` to see which days had the largest change in volume traded from the day before:" @@ -4292,7 +4292,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb3fe5ee-60ce-4e89-b324-730dddef5812", + "id": "400", "metadata": {}, "outputs": [], "source": [ @@ -4304,7 +4304,7 @@ }, { "cell_type": "markdown", - "id": "9a10d8a1-9f93-441b-8f9b-24f99a4e1460", + "id": "401", "metadata": {}, "source": [ "January 12th was when the news that Facebook changed its news feed product to focus more on content from a users' friends over the brands they follow. Given that Facebook's advertising is a key component of its business ([nearly 89% in 2017](https://www.investopedia.com/ask/answers/120114/how-does-facebook-fb-make-money.asp)), many shares were sold and the price dropped in panic:" @@ -4313,7 +4313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "93057d2a-802a-4dbd-8183-fff66f34fd87", + "id": "402", "metadata": {}, "outputs": [], "source": [ @@ -4322,7 +4322,7 @@ }, { "cell_type": "markdown", - "id": "4b0819b3-fc22-4c47-b314-6996d96ac3f6", + "id": "403", "metadata": {}, "source": [ "Throughout 2018, Facebook's stock price never had a low above $215:" @@ -4331,7 +4331,7 @@ { "cell_type": "code", "execution_count": null, - "id": "520832ad-38a3-40a7-bb54-31f9e101cd0e", + "id": "404", "metadata": {}, "outputs": [], "source": [ @@ -4340,7 +4340,7 @@ }, { "cell_type": "markdown", - "id": "a4c1363a-b454-46f0-8962-14f8dc28635a", + "id": "405", "metadata": {}, "source": [ "Facebook's OHLC (open, high, low, and close) prices all had at least one day they were at $215 or less:" @@ -4349,7 +4349,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7c41203a-d1e5-4892-b5cc-e892c7e98fc3", + "id": "406", "metadata": {}, "outputs": [], "source": [ @@ -4358,7 +4358,7 @@ }, { "cell_type": "markdown", - "id": "fcc0ebf9-8783-4039-8aff-538f6d0627e9", + "id": "407", "metadata": {}, "source": [ "### Binning" @@ -4366,7 +4366,7 @@ }, { "cell_type": "markdown", - "id": "7ac0c459-0b95-4989-853c-3df5525baea6", + "id": "408", "metadata": {}, "source": [ "When working with volume traded, we may be interested in ranges of volume rather than the exact values. No two days have the same volume traded:" @@ -4375,7 +4375,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1578664b-8daa-4167-9fc1-7c692f573e02", + "id": "409", "metadata": {}, "outputs": [], "source": [ @@ -4384,7 +4384,7 @@ }, { "cell_type": "markdown", - "id": "2e9762b4-6744-4635-8020-bcdb8ffdc926", + "id": "410", "metadata": {}, "source": [ "We can use `pd.cut()` to create 3 bins of even range in volume traded and name them.\n", @@ -4394,7 +4394,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4d51738e-fd22-42f6-8ea1-49af99817a32", + "id": "411", "metadata": {}, "outputs": [], "source": [ @@ -4404,7 +4404,7 @@ }, { "cell_type": "markdown", - "id": "95228c74-53f7-4eea-bb1f-70367ebf603f", + "id": "412", "metadata": {}, "source": [ "Let's look at the days with high trading volume:" @@ -4413,7 +4413,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ff52e285-e3ea-4da1-94a8-7c699012f4a5", + "id": "413", "metadata": {}, "outputs": [], "source": [ @@ -4422,7 +4422,7 @@ }, { "cell_type": "markdown", - "id": "3ac68cc0-3105-4e83-a7bf-d9187251d85e", + "id": "414", "metadata": {}, "source": [ "July 25th Facebook announced disappointing user growth and the stock tanked in the after hours:" @@ -4431,7 +4431,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e5f52172-cc0a-4082-8821-5b72a0af6c94", + "id": "415", "metadata": {}, "outputs": [], "source": [ @@ -4440,7 +4440,7 @@ }, { "cell_type": "markdown", - "id": "68c91ffc-6a2a-495d-b8c7-a9157decd66f", + "id": "416", "metadata": {}, "source": [ "Cambridge Analytica scandal broke on Saturday, March 17th, so we look at the Monday after for the numbers:" @@ -4449,7 +4449,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8b4a228f-d0ca-4aa3-9c41-d8a197a8242c", + "id": "417", "metadata": {}, "outputs": [], "source": [ @@ -4458,7 +4458,7 @@ }, { "cell_type": "markdown", - "id": "afca2c5f-87a7-4049-9aef-92101d97fbdc", + "id": "418", "metadata": {}, "source": [ "Since most days have similar volume, but a few are very large, we have very wide bins.\n", @@ -4468,7 +4468,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d78133da-5d28-4017-b51d-268dbeec29f8", + "id": "419", "metadata": {}, "outputs": [], "source": [ @@ -4482,7 +4482,7 @@ }, { "cell_type": "markdown", - "id": "0accee4c-17bf-4708-8051-fbd047455a1e", + "id": "420", "metadata": {}, "source": [ "If we split using quantiles, the bins will have roughly the same number of observations.\n", @@ -4492,7 +4492,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1cd773e6-5b03-4b20-a784-5108cc8a6ac8", + "id": "421", "metadata": {}, "outputs": [], "source": [ @@ -4502,7 +4502,7 @@ }, { "cell_type": "markdown", - "id": "a034be9e-3abf-4acd-9308-1ebd7f8d972e", + "id": "422", "metadata": {}, "source": [ "Notice the bins don't cover ranges of the same size anymore:" @@ -4511,7 +4511,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3f29e1d6-238d-4dd7-998b-f2e5c52c7a23", + "id": "423", "metadata": {}, "outputs": [], "source": [ @@ -4525,7 +4525,7 @@ }, { "cell_type": "markdown", - "id": "c4ae8eab-5b7c-42b9-858b-bc761d14b092", + "id": "424", "metadata": {}, "source": [ "### Applying functions" @@ -4533,7 +4533,7 @@ }, { "cell_type": "markdown", - "id": "78fa0507-a4f1-431f-91a8-0403cbfc0069", + "id": "425", "metadata": {}, "source": [ "We can use the `apply()` method to run the same operation on all columns (or rows) of the dataframe.\n", @@ -4543,7 +4543,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c71d3e91-c772-4afe-816b-1ee8ec3f3c2d", + "id": "426", "metadata": {}, "outputs": [], "source": [ @@ -4554,7 +4554,7 @@ }, { "cell_type": "markdown", - "id": "979ac66a-bfd1-4fd3-8ea1-eb8b3e5b7477", + "id": "427", "metadata": {}, "source": [ "Let's calculate the Z-scores of the TMIN, TMAX, and PRCP observations in Central Park in October 2018:" @@ -4563,7 +4563,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7f9b7fce-cd1b-4fc9-b7cc-9705ee9e968d", + "id": "428", "metadata": {}, "outputs": [], "source": [ @@ -4575,7 +4575,7 @@ }, { "cell_type": "markdown", - "id": "4e63b75b-5baa-4d75-b506-548e375bad38", + "id": "429", "metadata": {}, "source": [ "October 27th rained much more than the rest of the days:" @@ -4584,7 +4584,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76e8f8cb-36d2-4ad9-8dc0-49e968bed6a5", + "id": "430", "metadata": {}, "outputs": [], "source": [ @@ -4593,7 +4593,7 @@ }, { "cell_type": "markdown", - "id": "3cf0e3f8-3a4f-4378-84b9-db9a6daa4708", + "id": "431", "metadata": {}, "source": [ "Indeed, this day was much higher than the rest:" @@ -4602,7 +4602,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a965a32c-0c74-4166-8f66-92eba9d65dbb", + "id": "432", "metadata": {}, "outputs": [], "source": [ @@ -4611,7 +4611,7 @@ }, { "cell_type": "markdown", - "id": "f4c36adc-ac67-4254-8954-bb4fa20f6110", + "id": "433", "metadata": {}, "source": [ "When the function we want to apply isn't vectorized, we can:\n", @@ -4626,7 +4626,7 @@ { "cell_type": "code", "execution_count": null, - "id": "47b81fc2-2ebe-492f-bdcb-10421d65649b", + "id": "434", "metadata": {}, "outputs": [], "source": [ @@ -4639,7 +4639,7 @@ }, { "cell_type": "markdown", - "id": "31d5bf08-4529-4dd1-9763-66625537a444", + "id": "435", "metadata": {}, "source": [ "**A note about performance**\n", @@ -4651,7 +4651,7 @@ { "cell_type": "code", "execution_count": null, - "id": "efb83d3a-31eb-4a9a-b6e2-f5c6871a9840", + "id": "436", "metadata": {}, "outputs": [], "source": [ @@ -4701,7 +4701,7 @@ }, { "cell_type": "markdown", - "id": "9bddd10d-9863-41fd-8bb2-a2a38f3afa69", + "id": "437", "metadata": {}, "source": [ "## Using `groupby()`\n", @@ -4713,7 +4713,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a2b4449b-0615-4cb8-b84a-0624aa40bcb3", + "id": "438", "metadata": {}, "outputs": [], "source": [ @@ -4725,7 +4725,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f5ab9e73-a176-4ac9-987f-dd46f93acee2", + "id": "439", "metadata": {}, "outputs": [], "source": [ @@ -4739,7 +4739,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20f0e72a-663a-4286-adb4-1647f13cf44f", + "id": "440", "metadata": {}, "outputs": [], "source": [ @@ -4748,7 +4748,7 @@ }, { "cell_type": "markdown", - "id": "044c421c-663b-404f-97bc-4230b4442f88", + "id": "441", "metadata": {}, "source": [ "After we call `groupby()`, we can still select columns for aggregation:" @@ -4757,7 +4757,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a344ae03-ee34-474a-a74e-0a54fa263d52", + "id": "442", "metadata": {}, "outputs": [], "source": [ @@ -4766,7 +4766,7 @@ }, { "cell_type": "markdown", - "id": "497598eb-d65b-4ad2-acb8-03c1e2b3191a", + "id": "443", "metadata": {}, "source": [ "We can still provide a dictionary specifying the aggregations to perform, but passing a list for a column will result in a hierarchical index for the columns:" @@ -4775,7 +4775,7 @@ { "cell_type": "code", "execution_count": null, - "id": "588394b7-b35f-4157-a224-94d7d18e4cfc", + "id": "444", "metadata": {}, "outputs": [], "source": [ @@ -4790,7 +4790,7 @@ }, { "cell_type": "raw", - "id": "08f31003-e471-46d0-b734-40cd4898c30c", + "id": "445", "metadata": {}, "source": [ "The hierarchical index in the columns looks like this:" @@ -4799,7 +4799,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a7fd4d98-c6eb-475b-b381-d5f640852b90", + "id": "446", "metadata": {}, "outputs": [], "source": [ @@ -4808,7 +4808,7 @@ }, { "cell_type": "markdown", - "id": "164915dc-a46d-4945-99ec-5347cfe256d4", + "id": "447", "metadata": {}, "source": [ "Using a list comprehension, we can join the levels (in a tuple) with an `_` at each iteration: " @@ -4817,7 +4817,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26b6b06b-b7cd-4483-8ddc-58d736dac9d8", + "id": "448", "metadata": {}, "outputs": [], "source": [ @@ -4827,7 +4827,7 @@ }, { "cell_type": "markdown", - "id": "ac245fbb-f138-4ff2-ae64-bdcaa89f67ed", + "id": "449", "metadata": {}, "source": [ "## Exercises (3)" @@ -4836,7 +4836,7 @@ { "cell_type": "code", "execution_count": null, - "id": "08f04223-26cb-4bc8-8210-998da7426dd1", + "id": "450", "metadata": {}, "outputs": [], "source": [ @@ -4846,7 +4846,7 @@ }, { "cell_type": "markdown", - "id": "86e3a6f7-5225-408a-8766-ccd7d66503da", + "id": "451", "metadata": {}, "source": [ "For these exercises, you will be using the following datasets:" @@ -4855,7 +4855,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51e5f037-39e6-4f19-9dbb-8196f65be944", + "id": "452", "metadata": {}, "outputs": [], "source": [ @@ -4865,7 +4865,7 @@ }, { "cell_type": "markdown", - "id": "269830ec-43e0-40ca-9d75-0f1084286df6", + "id": "453", "metadata": {}, "source": [ "*The `faang.csv` dataset is a copy of what you should've obtained in Exercise 1 of the previous section.*" @@ -4873,7 +4873,7 @@ }, { "cell_type": "markdown", - "id": "1dccbf10-5465-407b-aeb5-fe9a59f1a2ec", + "id": "454", "metadata": {}, "source": [ "**Exercise 1**" @@ -4881,7 +4881,7 @@ }, { "cell_type": "markdown", - "id": "b948422c-c05a-495a-847b-f4d82b071228", + "id": "455", "metadata": {}, "source": [ "With the `earthquakes.csv file`, select all the earthquakes in Japan with a\n", @@ -4890,7 +4890,7 @@ }, { "cell_type": "markdown", - "id": "5ad78193-3c31-405b-9353-632199fe9cc3", + "id": "456", "metadata": {}, "source": [ "**Exercise 2**" @@ -4898,7 +4898,7 @@ }, { "cell_type": "markdown", - "id": "de8524fa-42dc-4d23-8563-d9d7c2ac23ad", + "id": "457", "metadata": {}, "source": [ "Create bins for each full number of magnitude (for example, the first bin is `(0, 1]`, the second is `(1, 2]`, and so on) with the `ml` magnitude type and count how many are in each bin." @@ -4906,7 +4906,7 @@ }, { "cell_type": "markdown", - "id": "04e2a521-5156-4758-b96f-b0a3866b2fd3", + "id": "458", "metadata": {}, "source": [ "**Exercise 3**" @@ -4914,7 +4914,7 @@ }, { "cell_type": "markdown", - "id": "30217da5-ad81-4dfb-bb98-c9344b1125e8", + "id": "459", "metadata": {}, "source": [ "Using the `faang.csv` file:\n", diff --git a/library_scipy.ipynb b/library_scipy.ipynb index 6746bbf9..23ba0197 100644 --- a/library_scipy.ipynb +++ b/library_scipy.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "d92307e3-d734-4d08-a8dc-ee8a201c3b6e", + "id": "0", "metadata": {}, "source": [ "# Scipy" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "c9a51b45-de42-4887-9244-f6cc1d74aa0e", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -68,7 +68,7 @@ }, { "cell_type": "markdown", - "id": "3edb3999-85e2-4cd5-bcfa-67693891bf6f", + "id": "2", "metadata": { "tags": [] }, @@ -78,7 +78,7 @@ }, { "cell_type": "markdown", - "id": "ad4e36dc-2e37-41ca-bc4e-48ea24975fe2", + "id": "3", "metadata": {}, "source": [ "Additional material for learning scipy, from the documentation, articles, videos or examples:\n", @@ -91,7 +91,7 @@ }, { "cell_type": "markdown", - "id": "00ac8e40-9a6e-4fda-bcd6-ca0b7bb0bfd4", + "id": "4", "metadata": {}, "source": [ "---" @@ -99,7 +99,7 @@ }, { "cell_type": "markdown", - "id": "6787e774-0b23-428a-abe2-b966c1a59047", + "id": "5", "metadata": { "tags": [] }, @@ -132,7 +132,7 @@ }, { "cell_type": "markdown", - "id": "d1e43724-68a1-4fdb-a846-dc1c926d3d4a", + "id": "6", "metadata": {}, "source": [ "## 2. Use case: Optimization\n", @@ -148,7 +148,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6d465eed", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -161,7 +161,7 @@ }, { "cell_type": "markdown", - "id": "13c30cb0", + "id": "8", "metadata": {}, "source": [ "Now we plot the function using `matplotlib`, a module for plotting described in another module of our course." @@ -170,7 +170,7 @@ { "cell_type": "code", "execution_count": null, - "id": "773c033e", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -186,7 +186,7 @@ }, { "cell_type": "markdown", - "id": "a068cb1d", + "id": "10", "metadata": {}, "source": [ "Visually (and algebraically) we can determine the minimum of this function to be at -2. \n", @@ -207,7 +207,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1da05563", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -219,7 +219,7 @@ }, { "cell_type": "markdown", - "id": "6e6f2efb", + "id": "12", "metadata": {}, "source": [ "As you can see from the output, running `minimze` results in an object with several attributes. \n", @@ -234,7 +234,7 @@ }, { "cell_type": "markdown", - "id": "14da283c", + "id": "13", "metadata": {}, "source": [ "### 2.2. Example: determining the gravity acceleration\n", @@ -255,7 +255,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7e353b31", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -271,7 +271,7 @@ }, { "cell_type": "markdown", - "id": "5296c58b", + "id": "15", "metadata": {}, "source": [ "Notice that we add a random number sampled from a Gaussian distribution with zero mean and standard deviation of 1e-4 seconds to the simulated values. \n", @@ -283,7 +283,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3496fa41", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -304,7 +304,7 @@ }, { "cell_type": "markdown", - "id": "f73c6797", + "id": "17", "metadata": {}, "source": [ "At this point we have all the data we need for estimating $g$ from our measurements. \n", @@ -323,7 +323,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9989e4f8", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -333,7 +333,7 @@ }, { "cell_type": "markdown", - "id": "35a674d5", + "id": "19", "metadata": {}, "source": [ "Now we can call the function:\n" @@ -342,7 +342,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1b0739ce", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -355,7 +355,7 @@ }, { "cell_type": "markdown", - "id": "ebf435ad", + "id": "21", "metadata": {}, "source": [ "Success! As you can see, the estimated value of $g$ is quite close to the real value. The discrepancy is in the order of magnitude of the standard deviation of the noise we add to the simulated measurements.\n", @@ -366,7 +366,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cea0f0a7", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -382,7 +382,7 @@ }, { "cell_type": "markdown", - "id": "2407da7c", + "id": "23", "metadata": {}, "source": [ "You can see that the curve with the estimated fall times given the estimated $g$ tracks the \"measurements\" very well.\n", @@ -391,7 +391,7 @@ }, { "cell_type": "markdown", - "id": "3b007c46", + "id": "24", "metadata": {}, "source": [ "### 2.3. Exercise: optimization 🌶️\n", @@ -404,7 +404,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1b64103f", + "id": "25", "metadata": {}, "outputs": [], "source": [ @@ -414,7 +414,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b14cd0b", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -433,7 +433,7 @@ }, { "cell_type": "markdown", - "id": "29bc762e", + "id": "27", "metadata": {}, "source": [ "## 3. Use case: spatial data\n", @@ -480,7 +480,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c3ff5b92", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -555,7 +555,7 @@ }, { "cell_type": "markdown", - "id": "59c264e7", + "id": "29", "metadata": {}, "source": [ "Now that we are able to generate and display the data, let's try and compute the variogram.\n", @@ -569,7 +569,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a5c6722f", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -613,7 +613,7 @@ }, { "cell_type": "markdown", - "id": "1a514857", + "id": "31", "metadata": {}, "source": [ "Now that we computed the variograms for angle difference and protein expression, we can plot them:" @@ -622,7 +622,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61ba7a47", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -637,7 +637,7 @@ }, { "cell_type": "markdown", - "id": "c02242b1", + "id": "33", "metadata": {}, "source": [ "### 3.4. Root finding\n", @@ -650,7 +650,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2d19abb6", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -670,7 +670,7 @@ }, { "cell_type": "markdown", - "id": "a7071332", + "id": "35", "metadata": {}, "source": [ "We recall that the fundamental theorem of algebra states that the above-defined $f(x)$ has exactly three roots in the complex numbers. It turns out that all the solutions of this $f(x)$ are real, as we see from the above plot.\n", @@ -681,7 +681,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d2334362", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -693,7 +693,7 @@ }, { "cell_type": "markdown", - "id": "c5cc5073", + "id": "37", "metadata": {}, "source": [ "Notice that the returned object from the function `root()` contains several elements. We just want the `.x` attribute. To get all three roots, we can simply just call them as a tuple:" @@ -702,7 +702,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1ac8c2aa", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -712,7 +712,7 @@ }, { "cell_type": "markdown", - "id": "d971715f", + "id": "39", "metadata": {}, "source": [ "### 3.5. Exercise: root finding 🌶️\n", @@ -723,7 +723,7 @@ { "cell_type": "code", "execution_count": null, - "id": "524524cc", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -733,7 +733,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38e951b9", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -750,7 +750,7 @@ }, { "cell_type": "markdown", - "id": "b29b1a31", + "id": "42", "metadata": {}, "source": [ "## 4. Linear algebra \n", @@ -788,7 +788,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75882633", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -802,7 +802,7 @@ }, { "cell_type": "markdown", - "id": "b251d168", + "id": "44", "metadata": {}, "source": [ "We now can verify if the solution is correct by computing $\\mathbf{A}\\hat{\\mathbf{x}}$, where $\\hat{\\mathbf{x}}$ is the solution obtained using `solve`. \n", @@ -812,7 +812,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b9c6cd43", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -821,7 +821,7 @@ }, { "cell_type": "markdown", - "id": "d569a7bc", + "id": "46", "metadata": {}, "source": [ "Indeed, we obtain the vector that (visually) looks like $\\mathbf{b}$.\n", @@ -831,7 +831,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ea5bc387", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -840,7 +840,7 @@ }, { "cell_type": "markdown", - "id": "94b9f1ad", + "id": "48", "metadata": {}, "source": [ "### 4.2. Triangular matrices\n", @@ -872,7 +872,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4a23af18", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -889,7 +889,7 @@ }, { "cell_type": "markdown", - "id": "cc573e53", + "id": "50", "metadata": {}, "source": [ "### 4.3. Toeplitz matrices\n", @@ -922,7 +922,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c9ac717f", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -937,7 +937,7 @@ }, { "cell_type": "markdown", - "id": "a74752c5", + "id": "52", "metadata": {}, "source": [ "### 4.4. Eigenvalue problems\n", @@ -948,7 +948,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6f1eb957", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -957,7 +957,7 @@ }, { "cell_type": "markdown", - "id": "a6c241f4", + "id": "54", "metadata": {}, "source": [ "Consider the tridiagonal matrix\n", @@ -977,7 +977,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b3e32867", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -989,7 +989,7 @@ }, { "cell_type": "markdown", - "id": "6189c4d5", + "id": "56", "metadata": {}, "source": [ "Let's check that this is correct:" @@ -998,7 +998,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1c3bf4c2", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -1009,7 +1009,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1669963e", + "id": "58", "metadata": {}, "outputs": [], "source": [ @@ -1019,7 +1019,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b6764b7", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -1028,7 +1028,7 @@ }, { "cell_type": "markdown", - "id": "f553b7f4", + "id": "60", "metadata": {}, "source": [ "### 4.5. Matrix decomposition: $LU$ decomposition\n", @@ -1039,7 +1039,7 @@ { "cell_type": "code", "execution_count": null, - "id": "80a6c3b3", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -1050,7 +1050,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2ea3a840", + "id": "62", "metadata": {}, "outputs": [], "source": [ @@ -1060,7 +1060,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6ed6ec79", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -1070,7 +1070,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cf5c6c69", + "id": "64", "metadata": {}, "outputs": [], "source": [ @@ -1079,7 +1079,7 @@ }, { "cell_type": "markdown", - "id": "e993b671", + "id": "65", "metadata": {}, "source": [ "### 4.6. Matrix decomposition: Choleski decomposition\n", @@ -1090,7 +1090,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cfaa3d23", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -1102,7 +1102,7 @@ { "cell_type": "code", "execution_count": null, - "id": "342b617d", + "id": "67", "metadata": {}, "outputs": [], "source": [ @@ -1112,7 +1112,7 @@ }, { "cell_type": "markdown", - "id": "8462df19", + "id": "68", "metadata": {}, "source": [ "### 4.7. Sparse matrices\n", @@ -1225,7 +1225,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7bac4476", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -1240,7 +1240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "34e0f398", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -1250,7 +1250,7 @@ }, { "cell_type": "markdown", - "id": "b1027a56", + "id": "71", "metadata": {}, "source": [ "Already for just a 5 x 5 starting matrix, the Kronecker sum is too big for any reasonable calculation! But we can use sparse matrices" @@ -1259,7 +1259,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28711b99", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -1274,7 +1274,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3866dca7", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -1283,7 +1283,7 @@ }, { "cell_type": "markdown", - "id": "9c095b81", + "id": "74", "metadata": {}, "source": [ "### 4.8. Exercise: $LU$ decomposition 🌶️\n", @@ -1303,7 +1303,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3ba8f8dd", + "id": "75", "metadata": {}, "outputs": [], "source": [ @@ -1313,7 +1313,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49ef2649", + "id": "76", "metadata": {}, "outputs": [], "source": [ @@ -1332,7 +1332,7 @@ }, { "cell_type": "markdown", - "id": "db28a566", + "id": "77", "metadata": {}, "source": [ "### 4.9. Exercise: the singular value decomposition (SVD) 🌶️\n", @@ -1347,7 +1347,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75fca200", + "id": "78", "metadata": {}, "outputs": [], "source": [ @@ -1357,7 +1357,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fed5876d", + "id": "79", "metadata": {}, "outputs": [], "source": [ @@ -1377,7 +1377,7 @@ }, { "cell_type": "markdown", - "id": "caf9f5bd", + "id": "80", "metadata": {}, "source": [ "## 5. Use case: interpolation\n", @@ -1388,7 +1388,7 @@ { "cell_type": "code", "execution_count": null, - "id": "37ba9655", + "id": "81", "metadata": {}, "outputs": [], "source": [ @@ -1402,7 +1402,7 @@ }, { "cell_type": "markdown", - "id": "b5449678", + "id": "82", "metadata": {}, "source": [ "Again -- we imagine that these are _collected_ data and not data which we have (artificially) generated by means of an analytical function. Now let's say that we want to know the values in between the above datapoints: we want to __interpolate__ between datapoints. We can do this using the `interp1d` library within `scipy.interpolate`:" @@ -1411,7 +1411,7 @@ { "cell_type": "code", "execution_count": null, - "id": "bd9e54be", + "id": "83", "metadata": {}, "outputs": [], "source": [ @@ -1425,7 +1425,7 @@ }, { "cell_type": "markdown", - "id": "753a7923", + "id": "84", "metadata": {}, "source": [ "We observe that this interpolation is not the best: it is very choppy and abrupt. Let's try a `cubic` interpolation now:" @@ -1434,7 +1434,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10445171", + "id": "85", "metadata": {}, "outputs": [], "source": [ @@ -1447,7 +1447,7 @@ }, { "cell_type": "markdown", - "id": "3c3cfe54", + "id": "86", "metadata": {}, "source": [ "### 5.1. Curve fitting\n", @@ -1466,7 +1466,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e4b529e6", + "id": "87", "metadata": {}, "outputs": [], "source": [ @@ -1477,7 +1477,7 @@ }, { "cell_type": "markdown", - "id": "353e3509", + "id": "88", "metadata": {}, "source": [ "Let's say that we don't want to interpolate, but we really want to fit to a curve: here, we assume that the curve is quadratic.\n", @@ -1487,7 +1487,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3e84d176", + "id": "89", "metadata": {}, "outputs": [], "source": [ @@ -1506,7 +1506,7 @@ { "cell_type": "code", "execution_count": null, - "id": "331bf1b7", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1515,7 +1515,7 @@ }, { "cell_type": "markdown", - "id": "60fdff3e", + "id": "91", "metadata": {}, "source": [ "### 5.2. Simple harmonic motion\n", @@ -1526,7 +1526,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cbcd6d38", + "id": "92", "metadata": {}, "outputs": [], "source": [ @@ -1548,7 +1548,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e2c4be62", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1557,7 +1557,7 @@ }, { "cell_type": "markdown", - "id": "dabf8430", + "id": "94", "metadata": {}, "source": [ "From elementary mechanics, we know that $\\omega=2\\pi f, f=1/T$, and $T \\approx 2$ seconds (by inspection). Thus, a good initial guess set of parameters is:\n", @@ -1571,7 +1571,7 @@ { "cell_type": "code", "execution_count": null, - "id": "02b99da8", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1584,7 +1584,7 @@ { "cell_type": "code", "execution_count": null, - "id": "beb1f860", + "id": "96", "metadata": {}, "outputs": [], "source": [ @@ -1594,7 +1594,7 @@ { "cell_type": "code", "execution_count": null, - "id": "192cbd96", + "id": "97", "metadata": {}, "outputs": [], "source": [ @@ -1604,7 +1604,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fad837be", + "id": "98", "metadata": {}, "outputs": [], "source": [ @@ -1614,7 +1614,7 @@ }, { "cell_type": "markdown", - "id": "f202fddf", + "id": "99", "metadata": {}, "source": [ "Now we can make a scatterplot of collected data and the curve using the fitted values for the parameters:" @@ -1623,7 +1623,7 @@ { "cell_type": "code", "execution_count": null, - "id": "46f213d3", + "id": "100", "metadata": {}, "outputs": [], "source": [ @@ -1633,7 +1633,7 @@ }, { "cell_type": "markdown", - "id": "b196016e", + "id": "101", "metadata": {}, "source": [ "How do we get the errors? We know from statistics that the errors are generally contained in the __covariance__ matrix, whereby the __standard deviation__ appears in the diagonal elements of the covariance matrix. `pcov` gives us the covariance matrix in `scipy`:" @@ -1642,7 +1642,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5108190d", + "id": "102", "metadata": {}, "outputs": [], "source": [ @@ -1652,7 +1652,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b96e7416", + "id": "103", "metadata": {}, "outputs": [], "source": [ @@ -1663,7 +1663,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1770d5de", + "id": "104", "metadata": {}, "outputs": [], "source": [ @@ -1672,7 +1672,7 @@ }, { "cell_type": "markdown", - "id": "b4a61070", + "id": "105", "metadata": {}, "source": [ "### 5.3. Exercise: curve fitting 🌶️\n", @@ -1683,7 +1683,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e412647a", + "id": "106", "metadata": {}, "outputs": [], "source": [ @@ -1698,7 +1698,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cdc309ea", + "id": "107", "metadata": {}, "outputs": [], "source": [ @@ -1708,7 +1708,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aafd199e", + "id": "108", "metadata": {}, "outputs": [], "source": [ @@ -1718,7 +1718,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74e1d68a", + "id": "109", "metadata": {}, "outputs": [], "source": [ @@ -1747,7 +1747,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5bb0abda", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1756,7 +1756,7 @@ }, { "cell_type": "markdown", - "id": "2d9521b3", + "id": "111", "metadata": {}, "source": [ "## 6. Fun with functions: the Legendre polynomials and the Bessel functions\n", @@ -1769,7 +1769,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b2890566", + "id": "112", "metadata": {}, "outputs": [], "source": [ @@ -1790,7 +1790,7 @@ }, { "cell_type": "markdown", - "id": "d1b70ee3", + "id": "113", "metadata": {}, "source": [ "The **Bessel functions** $J_a(x)$ are the solutions $y=J_a(x)$ to $x^2y'' + xy' + (x^2-\\alpha^2)y = 0$\n", @@ -1800,7 +1800,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a21df682", + "id": "114", "metadata": {}, "outputs": [], "source": [ @@ -1818,7 +1818,7 @@ }, { "cell_type": "markdown", - "id": "f1418019", + "id": "115", "metadata": {}, "source": [ "## Mathematical analysis\n", @@ -1836,7 +1836,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21cef1d0", + "id": "116", "metadata": {}, "outputs": [], "source": [ @@ -1846,7 +1846,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1311366d", + "id": "117", "metadata": {}, "outputs": [], "source": [ @@ -1858,7 +1858,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e6af07e2", + "id": "118", "metadata": {}, "outputs": [], "source": [ @@ -1869,7 +1869,7 @@ { "cell_type": "code", "execution_count": null, - "id": "148183fa", + "id": "119", "metadata": {}, "outputs": [], "source": [ @@ -1884,7 +1884,7 @@ }, { "cell_type": "markdown", - "id": "fc22d801", + "id": "120", "metadata": {}, "source": [ "## 8. Integration\n", @@ -1896,7 +1896,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6ac77701", + "id": "121", "metadata": {}, "outputs": [], "source": [ @@ -1909,7 +1909,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e0d8e863", + "id": "122", "metadata": {}, "outputs": [], "source": [ @@ -1918,7 +1918,7 @@ }, { "cell_type": "markdown", - "id": "abc62c48", + "id": "123", "metadata": {}, "source": [ "- we next consider the double integral $$\\int_0^1 \\int_{-x}^{x^2} \\sin(x+y^2) dy dx$$" @@ -1927,7 +1927,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f0bc6975", + "id": "124", "metadata": {}, "outputs": [], "source": [ @@ -1943,7 +1943,7 @@ { "cell_type": "code", "execution_count": null, - "id": "11f0b134", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1952,7 +1952,7 @@ }, { "cell_type": "markdown", - "id": "070e38dd", + "id": "126", "metadata": {}, "source": [ "### 8.1. Exercise: double integration 🌶️\n", @@ -1963,7 +1963,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d6421128", + "id": "127", "metadata": {}, "outputs": [], "source": [ @@ -1973,7 +1973,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c69437ac", + "id": "128", "metadata": {}, "outputs": [], "source": [ @@ -2001,7 +2001,7 @@ }, { "cell_type": "markdown", - "id": "044265e1", + "id": "129", "metadata": {}, "source": [ "## 9. Differential equations\n", @@ -2014,7 +2014,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19d84408", + "id": "130", "metadata": {}, "outputs": [], "source": [ @@ -2024,7 +2024,7 @@ }, { "cell_type": "markdown", - "id": "f854ed2a", + "id": "131", "metadata": {}, "source": [ "Need to provide to the interpreter all the information about the differential equation:" @@ -2033,7 +2033,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39181d87", + "id": "132", "metadata": {}, "outputs": [], "source": [ @@ -2044,7 +2044,7 @@ }, { "cell_type": "markdown", - "id": "47f12753", + "id": "133", "metadata": {}, "source": [ "Solve differential equation:" @@ -2053,7 +2053,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2e874017", + "id": "134", "metadata": {}, "outputs": [], "source": [ @@ -2066,7 +2066,7 @@ }, { "cell_type": "markdown", - "id": "a4383989", + "id": "135", "metadata": {}, "source": [ "We can then plot this:" @@ -2075,7 +2075,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cd437897", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -2085,7 +2085,7 @@ }, { "cell_type": "markdown", - "id": "14f713f7", + "id": "137", "metadata": {}, "source": [ "### 9.2. Exercise: first-order ODEs\n", @@ -2096,7 +2096,7 @@ { "cell_type": "code", "execution_count": null, - "id": "08d553b5", + "id": "138", "metadata": {}, "outputs": [], "source": [ @@ -2106,7 +2106,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e5b721e5", + "id": "139", "metadata": {}, "outputs": [], "source": [ @@ -2130,7 +2130,7 @@ }, { "cell_type": "markdown", - "id": "9ec72579", + "id": "140", "metadata": {}, "source": [ "### 9.3. Coupled first-order ODEs\n", @@ -2152,7 +2152,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7c6ba559", + "id": "141", "metadata": {}, "outputs": [], "source": [ @@ -2168,7 +2168,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5f631443", + "id": "142", "metadata": {}, "outputs": [], "source": [ @@ -2180,7 +2180,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3090aa53", + "id": "143", "metadata": {}, "outputs": [], "source": [ @@ -2195,7 +2195,7 @@ }, { "cell_type": "markdown", - "id": "a22f289c", + "id": "144", "metadata": {}, "source": [ "Here we can see that the solution depends on the set of initial conditions, as expected" @@ -2203,7 +2203,7 @@ }, { "cell_type": "markdown", - "id": "0c9f3445", + "id": "145", "metadata": {}, "source": [ "### 9.4. Second-order ODEs\n", @@ -2219,7 +2219,7 @@ { "cell_type": "code", "execution_count": null, - "id": "af7e4795", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -2235,7 +2235,7 @@ { "cell_type": "code", "execution_count": null, - "id": "666ddf1f", + "id": "147", "metadata": {}, "outputs": [], "source": [ @@ -2249,7 +2249,7 @@ }, { "cell_type": "markdown", - "id": "083cbd37", + "id": "148", "metadata": {}, "source": [ "## 10. Fourier transforms\n", @@ -2271,7 +2271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "aff80315", + "id": "149", "metadata": {}, "outputs": [], "source": [ @@ -2284,7 +2284,7 @@ }, { "cell_type": "markdown", - "id": "78ff57f9", + "id": "150", "metadata": {}, "source": [ "We can then compute the **fast Fourier transform** of this function:" @@ -2293,7 +2293,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36f04a06", + "id": "151", "metadata": {}, "outputs": [], "source": [ @@ -2309,7 +2309,7 @@ }, { "cell_type": "markdown", - "id": "78c0b68b", + "id": "152", "metadata": {}, "source": [ "Note that it's symmetric, which is true for any real-valued time series: its Fourier transform is symmetric, so what we actually have plotted above are positive frequencies up to half the time scale, and then goes over to the negative frequencies for the second half of the time scale." @@ -2318,7 +2318,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e0f05a03", + "id": "153", "metadata": {}, "outputs": [], "source": [ @@ -2330,7 +2330,7 @@ }, { "cell_type": "markdown", - "id": "a569b247", + "id": "154", "metadata": {}, "source": [ "### 11. Statistics\n", @@ -2347,7 +2347,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a643bc37", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -2356,7 +2356,7 @@ }, { "cell_type": "markdown", - "id": "db6afdc5", + "id": "156", "metadata": {}, "source": [ "Basic statistics" @@ -2365,7 +2365,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ec1d5935", + "id": "157", "metadata": {}, "outputs": [], "source": [ @@ -2375,7 +2375,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c099bd7b", + "id": "158", "metadata": {}, "outputs": [], "source": [ @@ -2385,7 +2385,7 @@ }, { "cell_type": "markdown", - "id": "67f5e967", + "id": "159", "metadata": {}, "source": [ "Probability distribution plotting:" @@ -2394,7 +2394,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9974da50", + "id": "160", "metadata": {}, "outputs": [], "source": [ @@ -2404,7 +2404,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0c9ed4e6", + "id": "161", "metadata": {}, "outputs": [], "source": [ @@ -2416,7 +2416,7 @@ }, { "cell_type": "markdown", - "id": "bc8fcf69", + "id": "162", "metadata": {}, "source": [ "Generating random variables:" @@ -2425,7 +2425,7 @@ { "cell_type": "code", "execution_count": null, - "id": "6988d795", + "id": "163", "metadata": {}, "outputs": [], "source": [ @@ -2435,7 +2435,7 @@ }, { "cell_type": "markdown", - "id": "8ef63280", + "id": "164", "metadata": {}, "source": [ "#### 11.2. the Gaussian distribution\n", @@ -2450,7 +2450,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4ab6e3c2", + "id": "165", "metadata": {}, "outputs": [], "source": [ @@ -2460,7 +2460,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f8498f37", + "id": "166", "metadata": {}, "outputs": [], "source": [ @@ -2478,7 +2478,7 @@ }, { "cell_type": "markdown", - "id": "135ed7aa", + "id": "167", "metadata": {}, "source": [ "#### 11.3. The multinomial distribution\n", @@ -2495,7 +2495,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fb25fed5", + "id": "168", "metadata": {}, "outputs": [], "source": [ @@ -2509,7 +2509,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f8d2aa92", + "id": "169", "metadata": {}, "outputs": [], "source": [ @@ -2520,7 +2520,7 @@ }, { "cell_type": "markdown", - "id": "140394c1", + "id": "170", "metadata": {}, "source": [ "### 12. Problems (freehand)\n", @@ -2540,7 +2540,7 @@ }, { "cell_type": "markdown", - "id": "9eb022d4", + "id": "171", "metadata": {}, "source": [ "#### 12.2. Newton's law of cooling 🌶️🌶️\n", @@ -2557,7 +2557,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2f3190d0", + "id": "172", "metadata": {}, "outputs": [], "source": [ @@ -2576,7 +2576,7 @@ }, { "cell_type": "markdown", - "id": "7e8cd596", + "id": "173", "metadata": {}, "source": [ "#### 12.3. The Lennard-Jones potential 🌶️🌶️\n", @@ -2591,7 +2591,7 @@ { "cell_type": "code", "execution_count": null, - "id": "09e1190e", + "id": "174", "metadata": {}, "outputs": [], "source": [ @@ -2603,7 +2603,7 @@ }, { "cell_type": "markdown", - "id": "0ec45329", + "id": "175", "metadata": {}, "source": [ "#### 12.4. Random number generation from your own distribution 🌶️🌶️🌶️\n", @@ -2617,7 +2617,7 @@ }, { "cell_type": "markdown", - "id": "00b12029", + "id": "176", "metadata": {}, "source": [ "#### 12.5. The finite square well 🌶️🌶️🌶️🌶️\n", @@ -2629,7 +2629,7 @@ }, { "cell_type": "markdown", - "id": "2595e991", + "id": "177", "metadata": {}, "source": [ "#### 12.6. the quintic polynomial 🌶️🌶️\n", diff --git a/manage_python_project.ipynb b/manage_python_project.ipynb index 9e97bd80..08973d3d 100644 --- a/manage_python_project.ipynb +++ b/manage_python_project.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "7f245f1b-c82d-4438-afd4-0a1ce799cc2c", + "id": "0", "metadata": {}, "source": [ "# Manage Python project" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "285d7182", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", @@ -72,7 +72,7 @@ }, { "cell_type": "markdown", - "id": "0444bffa", + "id": "2", "metadata": {}, "source": [ "# References\n", @@ -86,7 +86,7 @@ }, { "cell_type": "markdown", - "id": "0ce96799-6362-468c-9a17-63e6681d867e", + "id": "3", "metadata": {}, "source": [ "# Introduction\n", @@ -129,7 +129,7 @@ }, { "cell_type": "markdown", - "id": "1d0523ef", + "id": "4", "metadata": {}, "source": [ "## Preparatory exercise\n", @@ -145,7 +145,7 @@ }, { "cell_type": "markdown", - "id": "515f9eaa", + "id": "5", "metadata": {}, "source": [ "# The `pyproject.toml` file\n", @@ -158,7 +158,7 @@ }, { "cell_type": "markdown", - "id": "d8dcc9f0", + "id": "6", "metadata": {}, "source": [ "## The `project` section\n", @@ -236,7 +236,7 @@ }, { "cell_type": "markdown", - "id": "7799a4b5", + "id": "7", "metadata": {}, "source": [ "## Dependency specification\n", @@ -258,7 +258,7 @@ }, { "cell_type": "markdown", - "id": "a2ee531b", + "id": "8", "metadata": {}, "source": [ "## Optional dependencies\n", @@ -284,7 +284,7 @@ }, { "cell_type": "markdown", - "id": "12f74c64", + "id": "9", "metadata": {}, "source": [ "## Exercise on the `pyproject.toml` file.\n", @@ -297,7 +297,7 @@ }, { "cell_type": "markdown", - "id": "f70046bb", + "id": "10", "metadata": {}, "source": [ "# Pre-commit\n", @@ -311,7 +311,7 @@ }, { "cell_type": "markdown", - "id": "0a207766", + "id": "11", "metadata": {}, "source": [ "## Installation and running\n", @@ -345,7 +345,7 @@ }, { "cell_type": "markdown", - "id": "fa4fecb0", + "id": "12", "metadata": {}, "source": [ "## Configuration\n", @@ -372,7 +372,7 @@ }, { "cell_type": "markdown", - "id": "f6bac122", + "id": "13", "metadata": {}, "source": [ "## Supported hooks\n", @@ -384,7 +384,7 @@ }, { "cell_type": "markdown", - "id": "e4d81b6e", + "id": "14", "metadata": {}, "source": [ "### Auto-formatters\n", @@ -419,7 +419,7 @@ }, { "cell_type": "markdown", - "id": "54bf8b78", + "id": "15", "metadata": {}, "source": [ "### Linters\n", @@ -481,7 +481,7 @@ }, { "cell_type": "markdown", - "id": "93de525c", + "id": "16", "metadata": {}, "source": [ "### Type checks\n", @@ -497,7 +497,7 @@ }, { "cell_type": "markdown", - "id": "a3dec4af", + "id": "17", "metadata": {}, "source": [ "\n", @@ -523,7 +523,7 @@ }, { "cell_type": "markdown", - "id": "eb4c314c", + "id": "18", "metadata": {}, "source": [ "## Exercise on pre-commit\n", @@ -543,7 +543,7 @@ }, { "cell_type": "markdown", - "id": "d23720d8", + "id": "19", "metadata": {}, "source": [ "# Testing\n", @@ -558,7 +558,7 @@ }, { "cell_type": "markdown", - "id": "ffac1ab9", + "id": "20", "metadata": {}, "source": [ "## Types of tests\n", @@ -588,7 +588,7 @@ }, { "cell_type": "markdown", - "id": "57017e62", + "id": "21", "metadata": {}, "source": [ "## Installation\n", @@ -604,7 +604,7 @@ }, { "cell_type": "markdown", - "id": "25ca3ab0", + "id": "22", "metadata": {}, "source": [ "## Write your first unit test\n", @@ -639,7 +639,7 @@ }, { "cell_type": "markdown", - "id": "eac6d52b", + "id": "23", "metadata": {}, "source": [ "## Run the tests\n", @@ -656,7 +656,7 @@ }, { "cell_type": "markdown", - "id": "3600ded2", + "id": "24", "metadata": {}, "source": [ "## Test driven development (TDD)\n", @@ -680,7 +680,7 @@ }, { "cell_type": "markdown", - "id": "ade500df", + "id": "25", "metadata": {}, "source": [ "## Code coverage\n", @@ -757,7 +757,7 @@ }, { "cell_type": "markdown", - "id": "a6141d87", + "id": "26", "metadata": {}, "source": [ "# Documentation" @@ -765,7 +765,7 @@ }, { "cell_type": "markdown", - "id": "83352cbc", + "id": "27", "metadata": {}, "source": [ "## Why document?\n", @@ -781,7 +781,7 @@ }, { "cell_type": "markdown", - "id": "3761bef7", + "id": "28", "metadata": {}, "source": [ "## How document?\n", @@ -794,7 +794,7 @@ }, { "cell_type": "markdown", - "id": "3af92e4c", + "id": "29", "metadata": {}, "source": [ "## Comments\n", @@ -845,7 +845,7 @@ }, { "cell_type": "markdown", - "id": "b1565c35", + "id": "30", "metadata": {}, "source": [ "## Docstrings\n", @@ -886,7 +886,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5d72116a", + "id": "31", "metadata": { "tags": [] }, @@ -913,7 +913,7 @@ }, { "cell_type": "markdown", - "id": "66f3694a", + "id": "32", "metadata": {}, "source": [ "To get the docstring of a function, you can put a question mark after the function name and run the cell:" @@ -922,7 +922,7 @@ { "cell_type": "code", "execution_count": null, - "id": "da892ddb", + "id": "33", "metadata": { "tags": [] }, @@ -933,7 +933,7 @@ }, { "cell_type": "markdown", - "id": "c85a1fe2", + "id": "34", "metadata": {}, "source": [ "Another option is to use the `help` function:" @@ -942,7 +942,7 @@ { "cell_type": "code", "execution_count": null, - "id": "99f58380", + "id": "35", "metadata": { "tags": [] }, @@ -953,7 +953,7 @@ }, { "cell_type": "markdown", - "id": "8de46732", + "id": "36", "metadata": {}, "source": [ "The docstring is stored in the `__doc__` attribute of the function:" @@ -962,7 +962,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e31b6708", + "id": "37", "metadata": { "tags": [] }, @@ -973,7 +973,7 @@ }, { "cell_type": "markdown", - "id": "39d79fd3", + "id": "38", "metadata": {}, "source": [ "Therefore, changing the docstring is as easy as changing the value of the `__doc__` attribute:" @@ -982,7 +982,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1e552184", + "id": "39", "metadata": { "tags": [] }, @@ -994,7 +994,7 @@ }, { "cell_type": "markdown", - "id": "f8ecdd1f", + "id": "40", "metadata": {}, "source": [ "Docstrings can be used to document classes, methods, functions, and modules.\n", @@ -1005,7 +1005,7 @@ }, { "cell_type": "markdown", - "id": "dca79528", + "id": "41", "metadata": {}, "source": [ "## Type hints\n", @@ -1021,7 +1021,7 @@ { "cell_type": "code", "execution_count": null, - "id": "786bcb95", + "id": "42", "metadata": { "tags": [] }, @@ -1049,7 +1049,7 @@ { "cell_type": "code", "execution_count": null, - "id": "78f01d82", + "id": "43", "metadata": { "tags": [] }, @@ -1060,7 +1060,7 @@ }, { "cell_type": "markdown", - "id": "b7ba5f57", + "id": "44", "metadata": {}, "source": [ "In this case, the type information is present in the type hints, and the docstring focuses on providing additional context and information about the function, parameters, and return values." @@ -1068,7 +1068,7 @@ }, { "cell_type": "markdown", - "id": "5e6277e2", + "id": "45", "metadata": {}, "source": [ "## Markdown\n", @@ -1110,7 +1110,7 @@ }, { "cell_type": "markdown", - "id": "b321f549", + "id": "46", "metadata": {}, "source": [ "## README.md\n", @@ -1143,7 +1143,7 @@ }, { "cell_type": "markdown", - "id": "7c5acef6", + "id": "47", "metadata": {}, "source": [ "## Exercise on README.md\n", @@ -1153,7 +1153,7 @@ }, { "cell_type": "markdown", - "id": "469637d0", + "id": "48", "metadata": {}, "source": [ "## GitHub wiki\n", @@ -1178,7 +1178,7 @@ }, { "cell_type": "markdown", - "id": "d73c616f", + "id": "49", "metadata": {}, "source": [ "## Read the Docs\n", @@ -1201,7 +1201,7 @@ }, { "cell_type": "markdown", - "id": "fa7afdf1", + "id": "50", "metadata": {}, "source": [ "### Configuration\n", @@ -1219,7 +1219,7 @@ }, { "cell_type": "markdown", - "id": "06ac5c64", + "id": "51", "metadata": {}, "source": [ "### Writing the documentation\n", @@ -1232,7 +1232,7 @@ }, { "cell_type": "markdown", - "id": "167789b6", + "id": "52", "metadata": {}, "source": [ "### Building the documentation\n", @@ -1248,7 +1248,7 @@ }, { "cell_type": "markdown", - "id": "94478098", + "id": "53", "metadata": {}, "source": [ "### Deploying on Read the Docs\n", @@ -1291,7 +1291,7 @@ }, { "cell_type": "markdown", - "id": "3880146a", + "id": "54", "metadata": {}, "source": [ "# Releasing package\n", @@ -1304,7 +1304,7 @@ }, { "cell_type": "markdown", - "id": "49a90ce1", + "id": "55", "metadata": {}, "source": [ "## Why release?\n", @@ -1332,7 +1332,7 @@ }, { "cell_type": "markdown", - "id": "12c737bc", + "id": "56", "metadata": {}, "source": [ "## Update the version\n", @@ -1366,7 +1366,7 @@ }, { "cell_type": "markdown", - "id": "fa50d36e", + "id": "57", "metadata": {}, "source": [ "## Python Package Index (PyPI)\n", @@ -1406,7 +1406,7 @@ }, { "cell_type": "markdown", - "id": "48910204", + "id": "58", "metadata": {}, "source": [ "## Changelog\n", @@ -1417,7 +1417,7 @@ }, { "cell_type": "markdown", - "id": "35f24698", + "id": "59", "metadata": {}, "source": [ "### CHANGELOG.md\n", @@ -1466,7 +1466,7 @@ }, { "cell_type": "markdown", - "id": "c0915a09", + "id": "60", "metadata": {}, "source": [ "### GitHub releases\n", @@ -1493,7 +1493,7 @@ }, { "cell_type": "markdown", - "id": "0b1ee4cb", + "id": "61", "metadata": {}, "source": [ "# Automate things\n", @@ -1508,7 +1508,7 @@ }, { "cell_type": "markdown", - "id": "7f721e93", + "id": "62", "metadata": {}, "source": [ "## Testing\n", @@ -1560,7 +1560,7 @@ }, { "cell_type": "markdown", - "id": "2a2e0999", + "id": "63", "metadata": {}, "source": [ "## Exercise on testing automation\n", @@ -1571,7 +1571,7 @@ }, { "cell_type": "markdown", - "id": "ab5a31fe", + "id": "64", "metadata": {}, "source": [ "## Version update\n", @@ -1625,7 +1625,7 @@ }, { "cell_type": "markdown", - "id": "86c3ecee", + "id": "65", "metadata": {}, "source": [ "## Exercise on version update automation\n", @@ -1637,7 +1637,7 @@ }, { "cell_type": "markdown", - "id": "ca42772a", + "id": "66", "metadata": {}, "source": [ "## Releasing\n", @@ -1731,7 +1731,7 @@ }, { "cell_type": "markdown", - "id": "78322de9", + "id": "67", "metadata": {}, "source": [ "## Exercises on releasing automation\n", diff --git a/object_oriented_programming.ipynb b/object_oriented_programming.ipynb index b473709b..cd1441a1 100644 --- a/object_oriented_programming.ipynb +++ b/object_oriented_programming.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "6805e1bf-0da6-4ee5-9a1a-a2c2cd56fa9f", + "id": "0", "metadata": {}, "source": [ "# Object-oriented Programming" @@ -10,27 +10,29 @@ }, { "cell_type": "markdown", - "id": "d8056761-eb32-476c-91e3-63f3a8ed738f", + "id": "1", "metadata": {}, "source": [ "# Table of Contents\n", - "\n", - "- [References](#References)\n", - "- [A `class` as a blueprint of objects](#A-class-as-a-blueprint-of-objects)\n", - "- [Properties and methods](#Properties-and-methods)\n", - "- [Python's *special methods*](#Python's-*special-methods*)\n", - " - [`__str__` and `__repr__`](#__str__-and-__repr__)\n", - " - [Exercise 1: Ice cream scoop 🌶️](#Exercise-1:-Ice-cream-scoop-🌶️)\n", - " - [Comparison methods](#Comparison-methods)\n", - " - [Exercise 2: Ice cream bowl 🌶️🌶️](#Exercise-2:-Ice-cream-bowl-🌶️🌶️)\n", - "- [The `@property` keyword](#The-@property-keyword)\n", - "- [Quick glossary](#Quick-glossary)\n", - "- [Exercise 3: Intcode computer 🌶️🌶️🌶️](#Exercise-3:-Intcode-computer-🌶️🌶️🌶️)" + " - [Object-oriented Programming](#Object-oriented-Programming)\n", + " - [References](#References)\n", + " - [A `class` as a blueprint of objects](#A-class-as-a-blueprint-of-objects)\n", + " - [Properties and methods](#Properties-and-methods)\n", + " - [Python's *special methods*](#Python's-*special-methods*)\n", + " - [`__str__` and `__repr__`](#__str__-and-__repr__)\n", + " - [Exercise 1: Ice cream scoop 🌶️](#Exercise-1:-Ice-cream-scoop-🌶️)\n", + " - [Exercise 2: Ice cream bowl 🌶️🌶️](#Exercise-2:-Ice-cream-bowl-🌶️🌶️)\n", + " - [Comparison methods](#Comparison-methods)\n", + " - [Exercise 3: Ice cream shop 🌶️🌶️🌶️](#Exercise-3:-Ice-cream-shop-🌶️🌶️🌶️)\n", + " - [The `@property` keyword](#The-@property-keyword)\n", + " - [Quick glossary](#Quick-glossary)\n", + " - [Quiz](#Quiz)\n", + " - [Exercise 4: Intcode computer 🌶️🌶️🌶️🌶️](#Exercise-4:-Intcode-computer-🌶️🌶️🌶️🌶️)" ] }, { "cell_type": "markdown", - "id": "c7bce9ed-50a7-45e2-a741-799ec2a8d8c0", + "id": "2", "metadata": {}, "source": [ "## References" @@ -38,7 +40,7 @@ }, { "cell_type": "markdown", - "id": "81c741e8-ab31-4c0b-8651-66853f24af93", + "id": "3", "metadata": {}, "source": [ "- [Python classes (read)](https://www.py4e.com/html3/14-objects)\n", @@ -48,7 +50,7 @@ }, { "cell_type": "markdown", - "id": "58a632a3-dd6a-4f04-8cb6-d2a4293e79aa", + "id": "4", "metadata": { "tags": [] }, @@ -58,7 +60,7 @@ }, { "cell_type": "markdown", - "id": "5e7f1f46-913b-4c2e-a990-27466680e448", + "id": "5", "metadata": {}, "source": [ "Object-oriented programming (OOP) is probably the most well-know approach to programming. Almost every programming language in some way or another supports this paradigm.\n", @@ -71,7 +73,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7e4b4ddb-8db5-420d-a8fa-b2244b3a8580", + "id": "6", "metadata": { "tags": [] }, @@ -85,7 +87,7 @@ }, { "cell_type": "markdown", - "id": "fdc5f37f-b482-418b-ae7d-7ea3be574909", + "id": "7", "metadata": {}, "source": [ "In Python, to create a custom class we use the `class` keyword, and we can initialize class attributes in the special method `__init__`.\n", @@ -96,7 +98,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ac37eae7-2e2f-4f8d-9790-e14670deb0e2", + "id": "8", "metadata": { "tags": [] }, @@ -110,7 +112,7 @@ }, { "cell_type": "markdown", - "id": "36d6d922-7ec8-40bc-ae8b-fa912839331c", + "id": "9", "metadata": {}, "source": [ "The first argument (`self`) is automatically filled in by Python and contains **the object being created**. It's the way a class can modify itself, in some sense.\n", @@ -128,7 +130,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48cc5e1a-1912-4dab-8e4c-f325f8bc910e", + "id": "10", "metadata": { "tags": [] }, @@ -141,7 +143,7 @@ { "cell_type": "code", "execution_count": null, - "id": "443bd72f-5a36-4a6a-8889-bca4810d01f3", + "id": "11", "metadata": { "tags": [] }, @@ -153,7 +155,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2dcbc98a-2fa0-40c7-96aa-5cbad91127bb", + "id": "12", "metadata": { "tags": [] }, @@ -164,7 +166,7 @@ }, { "cell_type": "markdown", - "id": "0c64e447-436f-40fb-aa20-450cecf073cc", + "id": "13", "metadata": { "tags": [] }, @@ -174,7 +176,7 @@ }, { "cell_type": "markdown", - "id": "ed65342c-17eb-4109-a453-f97e72ca6f5d", + "id": "14", "metadata": {}, "source": [ "`width` and `height` are attributes of the `Rectangle` class. But since they are just values (they are **not** functions), we call them **properties**.\n", @@ -186,7 +188,7 @@ }, { "cell_type": "markdown", - "id": "60dc8f14-1602-4d55-8673-b4233bdc74bf", + "id": "15", "metadata": {}, "source": [ "You'll note that we were able to retrieve the `width` and `height` attributes (properties) using a dot notation, where we specify the object we are interested in, then a dot, then the attribute we are interested in." @@ -194,7 +196,7 @@ }, { "cell_type": "markdown", - "id": "c5808f6a-5a02-43f7-80b3-778071c05388", + "id": "16", "metadata": {}, "source": [ "We can add callable attributes to our class (methods), that will also be referenced using the dot notation.\n", @@ -205,7 +207,7 @@ { "cell_type": "code", "execution_count": null, - "id": "697f4809-cfde-456c-9f32-6667efa75799", + "id": "17", "metadata": { "tags": [] }, @@ -226,7 +228,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74e709b0-8f77-46b3-a5e5-8194f70b2bc0", + "id": "18", "metadata": { "tags": [] }, @@ -238,7 +240,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dcea9ef3-d76b-4137-a529-2cf8bf919f13", + "id": "19", "metadata": { "tags": [] }, @@ -249,7 +251,7 @@ }, { "cell_type": "markdown", - "id": "55c067a6-7988-4b5f-96c9-1053077f0192", + "id": "20", "metadata": {}, "source": [ "When we ran the above line of code, our object was `r1`, so when `area` was called, Python called the method `area` in the `Rectangle` class automatically, passing `r1` as the argument to the `self` parameter." @@ -257,7 +259,7 @@ }, { "cell_type": "markdown", - "id": "b4e939be-bc33-4d89-a7ec-1149ec05d9c0", + "id": "21", "metadata": { "tags": [] }, @@ -267,17 +269,17 @@ }, { "cell_type": "markdown", - "id": "0f394fcf-6dca-4867-b098-51e97adcd268", + "id": "22", "metadata": {}, "source": [ - "Special methods are methods that Python define automatically. If you define a custom class, then you are responsible of definining the **expected behavior** of these methods. Otherwise, Python will fallback to the default, built-in definition, or it will raise an error if it doesn't know what to do.\n", + "Special methods are methods that Python defines automatically. If you define a custom class, then you are responsible of defining the **expected behavior** of these methods. Otherwise, Python will fallback to the default, built-in definition, or it will raise an error if it doesn't know what to do.\n", "\n", "These are also called **dunder methods**, that is, \"double-underscore methods\", because their names look like `__method__`. There are special **attributes** as well." ] }, { "cell_type": "markdown", - "id": "9b348542-49ab-4d66-b92e-247b3824bbaf", + "id": "23", "metadata": { "tags": [] }, @@ -290,7 +292,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f7f1512b-a783-4304-b829-b17cef6c4a90", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -299,7 +301,7 @@ }, { "cell_type": "markdown", - "id": "7a2575df-fa79-4dfc-8800-759e6f55d333", + "id": "25", "metadata": {}, "source": [ "What happens if we try this with our `Rectangle` object?" @@ -308,7 +310,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0760e76b-04de-4d87-90d8-b942680b8698", + "id": "26", "metadata": { "tags": [] }, @@ -319,7 +321,7 @@ }, { "cell_type": "markdown", - "id": "da20832f-2313-4d9f-a57a-56bc7d0aa24e", + "id": "27", "metadata": {}, "source": [ "Not exactly what we might have expected. On the other hand, how is Python supposed to know how to display our rectangle as a string?\n", @@ -330,7 +332,7 @@ { "cell_type": "code", "execution_count": null, - "id": "23a32f1c-4161-48fa-b368-43c2b98f9a80", + "id": "28", "metadata": { "tags": [] }, @@ -353,7 +355,7 @@ }, { "cell_type": "markdown", - "id": "fe6534c4-1508-4e10-976b-e835c0070d19", + "id": "29", "metadata": {}, "source": [ "So now we could get a string from our object as follows:" @@ -362,7 +364,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8a2e73a3-2cf7-49f0-b0a4-5485e0ee3cac", + "id": "30", "metadata": { "tags": [] }, @@ -374,7 +376,7 @@ }, { "cell_type": "markdown", - "id": "f366dbbc-850d-447f-b63f-f7d282893275", + "id": "31", "metadata": {}, "source": [ "However, using the built-in `str` function still does not work 🤔" @@ -383,7 +385,7 @@ { "cell_type": "code", "execution_count": null, - "id": "da4219dd-ccff-4aae-af51-5dfd15a01723", + "id": "32", "metadata": { "tags": [] }, @@ -394,7 +396,7 @@ }, { "cell_type": "markdown", - "id": "851e869e-66d0-4cd5-a8cb-b4d51b274ac1", + "id": "33", "metadata": {}, "source": [ "This is where these special methods come in. When we call `str(r1)`, Python will first look to see if our class (`Rectangle`) has a special method called `__str__`.\n", @@ -407,7 +409,7 @@ { "cell_type": "code", "execution_count": null, - "id": "98c51761-ac50-4d53-a780-9332e6da3528", + "id": "34", "metadata": { "tags": [] }, @@ -432,7 +434,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9720291b-68dc-40ec-b692-e9b4da387904", + "id": "35", "metadata": { "tags": [] }, @@ -444,7 +446,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b5100468-087f-4256-b82d-2f6b8778f856", + "id": "36", "metadata": { "tags": [] }, @@ -455,7 +457,7 @@ }, { "cell_type": "markdown", - "id": "422b2608-71be-4e86-b886-e08be66d42e9", + "id": "37", "metadata": {}, "source": [ "However, in Jupyter, look what happens here:" @@ -464,7 +466,7 @@ { "cell_type": "code", "execution_count": null, - "id": "566a823a-48f4-4a5f-a88e-c93cbf05b268", + "id": "38", "metadata": { "tags": [] }, @@ -475,10 +477,10 @@ }, { "cell_type": "markdown", - "id": "0d793886-49fd-4300-87e5-664fc7a3eb3c", + "id": "39", "metadata": {}, "source": [ - "As you can see we still get that default. That's because here Python is **not** converting `r1` to a string, but instead looking for a string *representation* of the object. It is looking for the [`__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), which is defined as\n", + "As you can see we still get the default. That's because here Python is **not** converting `r1` to a string, but instead looking for a string *representation* of the object. It is looking for the [`__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), which is defined as\n", "\n", "> the “official” string representation of an object\n", "\n", @@ -488,7 +490,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2baf9528-84c6-4241-93f4-c224c647493e", + "id": "40", "metadata": { "tags": [] }, @@ -514,7 +516,7 @@ }, { "cell_type": "markdown", - "id": "fe8f0813-fff3-4bf9-96bd-d074ffe578de", + "id": "41", "metadata": { "tags": [] }, @@ -525,7 +527,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b49d042f-6784-422d-9591-d49b9a36d6e9", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -534,7 +536,7 @@ }, { "cell_type": "markdown", - "id": "77399991-d4a9-403a-852a-c8c224835a7f", + "id": "43", "metadata": {}, "source": [ "Define a class `Scoop` that represents a single scoop of ice cream. Each scoop should have a **single** attribute, `flavor`, a string that you can initialize when you create the instance of `Scoop`.\n", @@ -543,35 +545,91 @@ "\n", "
\n", "

Question

\n", - " Complete the solution function such that it creates three instances of the Scoop class with the following flavors: chocolate, vanilla, persimmon. This function should return a list that collects the string representations of the ice cream scoops.\n", + " Complete the solution function such that it creates an instance of the Scoop class for every flavor contained in the argument flavors. This function should return a list that collects the string representations of the ice cream scoops.\n", "
" ] }, { "cell_type": "code", "execution_count": null, - "id": "cb1bef70-3de4-480e-83cd-a7e52c8d02a0", + "id": "44", "metadata": { "tags": [] }, "outputs": [], "source": [ "%%ipytest\n", - "class Scoop:\n", - " \"\"\"A class representing a single scoop of ice cream\"\"\"\n", - " # Write your class implementation here\n", "\n", + "def solution_ice_cream_scoop(flavors: tuple[str]) -> list[str]:\n", "\n", - "flavors = # TODO: create a tuple containing the flavors\n", + " class Scoop:\n", + " \"\"\"A class representing a single scoop of ice cream\"\"\"\n", + " # Write your class implementation here\n", + "\n", + " # Write your solution here\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "45", + "metadata": { + "tags": [] + }, + "source": [ + "### Exercise 2: Ice cream bowl 🌶️🌶️" + ] + }, + { + "cell_type": "markdown", + "id": "46", + "metadata": {}, + "source": [ + "Create a class `Bowl` that can hold many ice cream scoops, as many as you like. You *should use* the custom class you created in the previous exercise.\n", + "\n", + "The `Bowl` class should have a method called `add_scoops()` that accepts **variable number** of scoops.\n", + "\n", + "
\n", + "

Hint

\n", + " In the __init__ method of the Bowl class, you should define an attribute that acts as a container to hold the scoops you might want to add.\n", + "
\n", + "\n", + "
\n", + "

Question

\n", + " Complete the solution function such that it creates a bowl of scoops with every flavor contained in the argument flavors. The output of this function should be a string that reports the content of the bowl you just created.\n", + "
\n", + "\n", + "For example:\n", + "\n", + "```\n", + "Ice cream bowl with chocolate, vanilla, stracciatella scoops\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "%%ipytest\n", + " \n", + "def solution_ice_cream_bowl(flavors: tuple[str]) -> str:\n", + "\n", + " class Bowl:\n", + " \"\"\"A class representing a bowl of ice cream scoops\"\"\"\n", + " # Write your class implementation here\n", "\n", - "def solution_ice_cream_scoop(flavors: tuple[str]) -> list[str]:\n", " # Write your solution here\n", " pass" ] }, { "cell_type": "markdown", - "id": "9f5daf4d-2909-4778-b450-ca567acf773a", + "id": "48", "metadata": { "tags": [] }, @@ -581,7 +639,7 @@ }, { "cell_type": "markdown", - "id": "f61058a3-bb5e-4dc7-9051-f0681147cf81", + "id": "49", "metadata": {}, "source": [ "How about the comparison operator, such as `==`? How can we tell Python how it should compare two different rectangles?" @@ -590,7 +648,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c896e204-080d-4dc1-bcec-970ad6982672", + "id": "50", "metadata": { "tags": [] }, @@ -603,7 +661,7 @@ { "cell_type": "code", "execution_count": null, - "id": "13d465a7-86d7-49b1-9643-4c90252a0b95", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -612,7 +670,7 @@ }, { "cell_type": "markdown", - "id": "150f6e2c-a2a3-40a8-a804-0411957691ea", + "id": "52", "metadata": {}, "source": [ "As you can see, Python does not consider `r1` and `r2` as equal (using the `==` operator). Again, how is Python supposed to know that two rectangle objects with the same height and width should be considered equal?" @@ -620,7 +678,7 @@ }, { "cell_type": "markdown", - "id": "dcf00b20-6770-410c-82f5-dea06f312984", + "id": "53", "metadata": {}, "source": [ "We just need to tell Python how to do it, using the special method `__eq__`. Let's see how:" @@ -629,7 +687,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b430191f-3c01-494c-8b94-9fe1871a8c9f", + "id": "54", "metadata": { "tags": [] }, @@ -667,7 +725,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a02072db-f86d-44bc-a786-4c93c21a2bbf", + "id": "55", "metadata": { "tags": [] }, @@ -679,7 +737,7 @@ }, { "cell_type": "markdown", - "id": "1b1baaf9-830f-4366-924e-ee35fd6387bf", + "id": "56", "metadata": {}, "source": [ "We now have two **different** objects, two instances of our `Rectangle` class. In fact, we can check that the two objects are different with the `is` operator" @@ -688,7 +746,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d2f0184d-09c1-44b7-b168-a59373180d1b", + "id": "57", "metadata": { "tags": [] }, @@ -699,7 +757,7 @@ }, { "cell_type": "markdown", - "id": "38419127-8417-4ae6-8ba4-7b5669aa9d68", + "id": "58", "metadata": {}, "source": [ "However, they are **equal** according to our `__eq__` function: rectangles are considered equal if their widths and heights are equal" @@ -708,7 +766,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2cb43f75-fd03-46d6-83d8-98c1d56e538b", + "id": "59", "metadata": { "tags": [] }, @@ -720,7 +778,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a91def65-ce17-49cd-aa1a-e1f8c4dec190", + "id": "60", "metadata": { "tags": [] }, @@ -732,7 +790,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b8108843-2b7b-41f8-8e82-e0dfa8e6163a", + "id": "61", "metadata": { "tags": [] }, @@ -743,7 +801,7 @@ }, { "cell_type": "markdown", - "id": "59566912-de9e-4768-a683-1f7f279f7d1b", + "id": "62", "metadata": {}, "source": [ "And if we try to compare our Rectangle to a different type:" @@ -752,7 +810,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e147e541-3ff7-43ce-a530-4f088fb8ef9c", + "id": "63", "metadata": { "tags": [] }, @@ -763,15 +821,15 @@ }, { "cell_type": "markdown", - "id": "72254316-200d-4a6d-bf93-d669f041c08b", + "id": "64", "metadata": {}, "source": [ - "That's because our `Rectangle` class automatically return `False` if we try to compare for equality an instance of `Rectangle` and any other Python object" + "That's because our `Rectangle` class automatically returns `False` if we try to compare for equality an instance of `Rectangle` and any other Python object." ] }, { "cell_type": "markdown", - "id": "38c920c6-d21c-41f9-b45c-65352822c3e5", + "id": "65", "metadata": {}, "source": [ "Here's our final class, without any `print` statement – remember, we should try to avoid side-effects when they are **not** necessary:" @@ -780,7 +838,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b4982727-ac70-4b25-9a92-6171228637a8", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -810,7 +868,7 @@ }, { "cell_type": "markdown", - "id": "ea2c70e3-e22b-4064-9159-61275d65b143", + "id": "67", "metadata": {}, "source": [ "What about `<`, `>`, `<=`, etc.?\n", @@ -822,7 +880,7 @@ }, { "cell_type": "markdown", - "id": "d7d1ffe1-92f4-438a-8e26-02c0c8382552", + "id": "68", "metadata": {}, "source": [ "
\n", @@ -834,7 +892,7 @@ { "cell_type": "code", "execution_count": null, - "id": "64d77b6d-7051-4f4c-a2eb-cece6c6eb58b", + "id": "69", "metadata": { "tags": [] }, @@ -873,7 +931,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f1427ccd-44e2-4356-aff8-d15aa4c2cff2", + "id": "70", "metadata": { "tags": [] }, @@ -886,7 +944,7 @@ { "cell_type": "code", "execution_count": null, - "id": "856d1822-36f8-48ca-b49f-76cdd10f9634", + "id": "71", "metadata": {}, "outputs": [], "source": [ @@ -896,7 +954,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0b9e5562-9c54-4ff4-bde1-82fb65e2c65e", + "id": "72", "metadata": {}, "outputs": [], "source": [ @@ -905,7 +963,7 @@ }, { "cell_type": "markdown", - "id": "14f23dc5-1764-47c0-8dfc-0ec3b7ab50fe", + "id": "73", "metadata": {}, "source": [ "What about `>`?" @@ -914,7 +972,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8208c603-a24f-4f73-8429-cd9e83143024", + "id": "74", "metadata": {}, "outputs": [], "source": [ @@ -923,7 +981,7 @@ }, { "cell_type": "markdown", - "id": "519f1390-5087-4415-a1af-89708fc4ccfd", + "id": "75", "metadata": {}, "source": [ "How did that work? We did not define a `__gt__` method.\n", @@ -933,7 +991,7 @@ }, { "cell_type": "markdown", - "id": "020909fe-2266-4e03-9d53-477596dc03d4", + "id": "76", "metadata": {}, "source": [ "Of course, `<=` is not going to magically work!" @@ -942,7 +1000,7 @@ { "cell_type": "code", "execution_count": null, - "id": "be964fd3-0615-4424-8d4f-885918216bad", + "id": "77", "metadata": {}, "outputs": [], "source": [ @@ -951,65 +1009,57 @@ }, { "cell_type": "markdown", - "id": "4abfe0ba-c893-4ffd-b40b-5931821bcc62", - "metadata": { - "tags": [] - }, + "id": "78", + "metadata": {}, "source": [ - "### Exercise 2: Ice cream bowl 🌶️🌶️" + "### Exercise 3: Ice cream shop 🌶️🌶️🌶️" ] }, { "cell_type": "markdown", - "id": "7f366029-6fa1-48f9-95ee-578b02addecd", + "id": "79", "metadata": {}, "source": [ - "Create a class `Bowl` that can hold many ice cream scoops, as many as you like. You *should use* the custom class you created in the previous exercise.\n", + "Create a class `Shop` that sells many ice cream flavours. \n", "\n", - "The `Bowl` class should have a method called `add_scoops()` that accept **variable number** of scoops.\n", + "The `Shop` class should implement the comparison methods `__eq__`, `__lt__`, `__le__`.\n", "\n", "
\n", - "

Hint

\n", - " In the __init__ method of the Bowl class, you should define an attribute that acts as a container to hold the scoops you might want to add\n", + "

Hints

\n", + "
    \n", + "
  • In the __init__ method of the Shop class, you should define an attribute that acts as a container to hold the available flavours.
  • \n", + "
  • You can use __eq__ and __lt__ to define __le__.
  • \n", + "
\n", "
\n", "\n", "
\n", "

Question

\n", - " Complete the solution function that creates a bowl of three scoops with flavors chocolate, vanilla, and stracciatella. The output of this function should be a string that reports the content of the bowl just created.\n", - "
\n", - "\n", - "For example:\n", - "\n", - "```\n", - "Ice cream bowl with chocolate, vanilla, stracciatella scoops\n", - "```" + " Complete the solution function so that it creates two ice cream shops. Shop 1 should sell the flavors provided by the parameter flavor_1 and Shop 2 should sell the flavors provided by the parameter flavor_2. The output of this function should be a boolean value: Does Shop 1 sell fewer or the same number of flavors as Shop 2?\n", + "
" ] }, { "cell_type": "code", "execution_count": null, - "id": "0a634345-9799-4d1d-967b-9634c5672e5f", - "metadata": { - "tags": [] - }, + "id": "80", + "metadata": {}, "outputs": [], "source": [ "%%ipytest\n", - "class Bowl:\n", - " \"\"\"A class representing a bowl of ice cream scoops\"\"\"\n", - " # Write your class implementation here\n", "\n", + "def solution_ice_cream_shop(flavors_1: list[str], flavors_2: list[str]) -> bool:\n", + "\n", + " class Shop:\n", + " \"\"\"A class representing an ice cream shop\"\"\"\n", + " # Write your class implementation here\n", "\n", - "flavors = # TODO: create a tuple containing the flavors\n", - " \n", - "def solution_ice_cream_bowl(flavors: tuple[str]) -> str:\n", " # Write your solution here\n", " pass" ] }, { "cell_type": "markdown", - "id": "e99e8fd7-48c0-415a-8ef4-ef4526343087", + "id": "81", "metadata": { "tags": [] }, @@ -1019,7 +1069,7 @@ }, { "cell_type": "markdown", - "id": "60cfa6f1-c3db-4cb7-a932-66ba094cf82b", + "id": "82", "metadata": {}, "source": [ "A question you might have about our `Rectangle` class is the following: why should we **call** a function to return its area? Isn't area a **property** of a rectangle?\n", @@ -1030,7 +1080,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12a9a008-45a7-43d1-9fcd-54e25075a743", + "id": "83", "metadata": { "tags": [] }, @@ -1041,7 +1091,7 @@ }, { "cell_type": "markdown", - "id": "248e46a2-3a3c-49e6-acf0-ab74439a5b8e", + "id": "84", "metadata": {}, "source": [ "It would tell us that `r1.area` is in fact an object. It's actually a **function**" @@ -1050,7 +1100,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1fa4af40-e7a4-4695-a200-08dc84d15b1c", + "id": "85", "metadata": { "tags": [] }, @@ -1061,7 +1111,7 @@ }, { "cell_type": "markdown", - "id": "bcc38adc-698d-4f40-ad0a-e5f3d11dfaa0", + "id": "86", "metadata": {}, "source": [ "Python provides you the special keyword `@property`. We are not going into the details of what this keyword does, but here's how you can use it in your classes to make them more \"user-friendly\":" @@ -1070,7 +1120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "466f0f14-8eb7-4cde-b02b-bf563784d7d2", + "id": "87", "metadata": { "tags": [] }, @@ -1098,7 +1148,7 @@ }, { "cell_type": "markdown", - "id": "78420f30-90ea-429c-aa6d-6b29c81d7cad", + "id": "88", "metadata": {}, "source": [ "You can simply add `@property` **just above** the line that defines your property. For example, the `def area()` or `def perimeter()` functions above." @@ -1107,7 +1157,7 @@ { "cell_type": "code", "execution_count": null, - "id": "cb506495-b079-4016-b087-7e49b3a6b95e", + "id": "89", "metadata": { "tags": [] }, @@ -1122,7 +1172,7 @@ }, { "cell_type": "markdown", - "id": "852b0c5b-3c41-4d7c-9d72-c1f86d52d5ff", + "id": "90", "metadata": {}, "source": [ "If you want to learn more about the `@property` keyword, you can check out [this link](https://docs.python.org/3/library/functions.html#property). **Beware**, it's rather advanced stuff! If it's your first time with Python, just skip it for the time being." @@ -1130,7 +1180,7 @@ }, { "cell_type": "markdown", - "id": "d91ad47d-5508-4e5c-9e29-c794332deafc", + "id": "91", "metadata": { "tags": [] }, @@ -1140,7 +1190,7 @@ }, { "cell_type": "markdown", - "id": "6092881f-1af2-4655-9e1a-543774edc157", + "id": "92", "metadata": {}, "source": [ "\n", @@ -1157,7 +1207,7 @@ }, { "cell_type": "markdown", - "id": "e1c92732-f58c-4afa-9212-ae8231784725", + "id": "93", "metadata": { "tags": [] }, @@ -1167,17 +1217,45 @@ }, { "cell_type": "markdown", - "id": "419b5378-ff17-4ed3-8203-97c132918cb7", + "id": "94", + "metadata": {}, + "source": [ + "## Quiz\n", + "\n", + "Run the following cell to test your knowledge with a small quiz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95", + "metadata": {}, + "outputs": [], + "source": [ + "from tutorial import object_oriented_programming as oop\n", + "\n", + "oop.OopQuiz()" + ] + }, + { + "cell_type": "markdown", + "id": "96", "metadata": { "tags": [] }, "source": [ - "## Exercise 3: Intcode computer 🌶️🌶️🌶️" + "## Exercise 4: Intcode computer 🌶️🌶️🌶️🌶️\n", + "\n", + "
\n", + "

Note

\n", + " This is a recap exercise of intermediate difficulty.\n", + " If you never used classes or objects before, please try to solve and understand the previous exercises first.\n", + "
" ] }, { "cell_type": "markdown", - "id": "ce95cc4a-9dc4-4da5-b906-9ab3a85fda5e", + "id": "97", "metadata": {}, "source": [ "An **Intcode program** is a list of integers separated by commas (e.g. `1,0,0,3,99`). The first number is called \"position `0`\". Each number represents either an **opcode** or a **position**.\n", @@ -1228,7 +1306,7 @@ }, { "cell_type": "markdown", - "id": "b2f287fe-0d6b-4a42-89e5-d331f502d91c", + "id": "98", "metadata": {}, "source": [ "
\n", @@ -1239,7 +1317,7 @@ }, { "cell_type": "markdown", - "id": "9ac11838-bcd1-4c7a-82e4-e89bc719f2c2", + "id": "99", "metadata": {}, "source": [ "Here are the initial and final states of a few small programs:\n", @@ -1251,7 +1329,7 @@ }, { "cell_type": "markdown", - "id": "1793c96c-0690-4c1f-8dda-72ed924497ca", + "id": "100", "metadata": {}, "source": [ "
\n", @@ -1267,22 +1345,29 @@ { "cell_type": "code", "execution_count": null, - "id": "e5fa75aa-336f-4694-b258-ca4f70115d05", + "id": "101", "metadata": { "tags": [] }, "outputs": [], "source": [ - "%%ipytest\n", - "class Computer:\n", - " \"\"\"An Intcode computer class\"\"\"\n", - " # Write your class implementation here\n", - "\n", - " \n", + "%%ipytest \n", "def solution_intcode_computer(intcode: str) -> int:\n", + " class Computer:\n", + " \"\"\"An Intcode computer class\"\"\"\n", + " # Write your class implementation here\n", + "\n", " # Write your solution function here\n", " pass" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "102", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -1301,7 +1386,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.14" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/object_oriented_programming_advanced.ipynb b/object_oriented_programming_advanced.ipynb index 386cf31e..15724cc0 100644 --- a/object_oriented_programming_advanced.ipynb +++ b/object_oriented_programming_advanced.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "6805e1bf-0da6-4ee5-9a1a-a2c2cd56fa9f", + "id": "0", "metadata": {}, "source": [ "# Advanced Object-oriented Programming" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "0225c10a", + "id": "1", "metadata": {}, "source": [ "## Table of Contents\n", @@ -45,7 +45,7 @@ }, { "cell_type": "markdown", - "id": "c7bce9ed-50a7-45e2-a741-799ec2a8d8c0", + "id": "2", "metadata": {}, "source": [ "## References" @@ -53,7 +53,7 @@ }, { "cell_type": "markdown", - "id": "8b4a8b3a", + "id": "3", "metadata": {}, "source": [ "- [super()](https://docs.python.org/3/library/functions.html#super)\n", @@ -63,7 +63,7 @@ }, { "cell_type": "markdown", - "id": "3de88ef0", + "id": "4", "metadata": {}, "source": [ "## Inheritance\n", @@ -74,7 +74,7 @@ }, { "cell_type": "markdown", - "id": "c25313f3", + "id": "5", "metadata": {}, "source": [ "### Single Inheritance\n", @@ -88,7 +88,7 @@ }, { "cell_type": "markdown", - "id": "5ba23da2", + "id": "6", "metadata": {}, "source": [ "Let's create a simple example in Python.\n", @@ -98,7 +98,7 @@ { "cell_type": "code", "execution_count": null, - "id": "629b2cab", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -112,7 +112,7 @@ }, { "cell_type": "markdown", - "id": "37e41742", + "id": "8", "metadata": {}, "source": [ "From your base class, you can define as many derived classes as you'd like.\n", @@ -128,7 +128,7 @@ { "cell_type": "code", "execution_count": null, - "id": "91d86d83", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -150,7 +150,7 @@ }, { "cell_type": "markdown", - "id": "b5a44c1f", + "id": "10", "metadata": {}, "source": [ "Now we can create instances of `Dog` and `Cat`: " @@ -159,7 +159,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1e5814dd", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -169,7 +169,7 @@ }, { "cell_type": "markdown", - "id": "b60cf7e6", + "id": "12", "metadata": {}, "source": [ "Let's see what happens when you call each instance's methods:" @@ -178,7 +178,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e44f6aa5", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -189,7 +189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d671e086", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -199,7 +199,7 @@ }, { "cell_type": "markdown", - "id": "03874772", + "id": "15", "metadata": {}, "source": [ "Of course, you can always use the base class `Animal` **as is**.\n", @@ -209,7 +209,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f19e1bd1", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -219,7 +219,7 @@ }, { "cell_type": "markdown", - "id": "c3fe1147", + "id": "17", "metadata": {}, "source": [ "### Multiple Inheritance\n", @@ -232,7 +232,7 @@ }, { "cell_type": "markdown", - "id": "3ac3b8d1", + "id": "18", "metadata": {}, "source": [ "To do that, we first define a new class." @@ -241,7 +241,7 @@ { "cell_type": "code", "execution_count": null, - "id": "06f2d826", + "id": "19", "metadata": {}, "outputs": [], "source": [ @@ -255,7 +255,7 @@ }, { "cell_type": "markdown", - "id": "0d325984", + "id": "20", "metadata": {}, "source": [ "Then, we create a derived class that inherits from two base classes. Notice that:\n", @@ -266,7 +266,7 @@ { "cell_type": "code", "execution_count": null, - "id": "64486254", + "id": "21", "metadata": {}, "outputs": [], "source": [ @@ -281,7 +281,7 @@ }, { "cell_type": "markdown", - "id": "128a9e86", + "id": "22", "metadata": {}, "source": [ "We can also call all methods inherited from each parent." @@ -290,7 +290,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49a3341f", + "id": "23", "metadata": {}, "outputs": [], "source": [ @@ -303,7 +303,7 @@ }, { "cell_type": "markdown", - "id": "dbfca489", + "id": "24", "metadata": {}, "source": [ "While multiple inheritance can be powerful, it can also lead to complexities and potential conflicts, so it should only be used when really needed.\n", @@ -313,7 +313,7 @@ }, { "cell_type": "markdown", - "id": "bc2b9384", + "id": "25", "metadata": {}, "source": [ "### Composition\n", @@ -328,7 +328,7 @@ }, { "cell_type": "markdown", - "id": "45b2d6ef", + "id": "26", "metadata": {}, "source": [ "Let's first create the classes for the `Engine` and the `Wheels` of a vehicle:" @@ -337,7 +337,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d8cd5291", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -362,7 +362,7 @@ }, { "cell_type": "markdown", - "id": "7c1d7152", + "id": "28", "metadata": {}, "source": [ "Then we can create a car, which has one engine and four wheels.\n", @@ -374,7 +374,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b25389af", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -397,7 +397,7 @@ { "cell_type": "code", "execution_count": null, - "id": "df993de3", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -409,7 +409,7 @@ }, { "cell_type": "markdown", - "id": "3afc1e3b", + "id": "31", "metadata": {}, "source": [ "### `super()`\n", @@ -422,7 +422,7 @@ }, { "cell_type": "markdown", - "id": "74253542", + "id": "32", "metadata": {}, "source": [ "Let's re-write class `Dog`, which is a subclass of `Animal`.\n", @@ -432,7 +432,7 @@ { "cell_type": "code", "execution_count": null, - "id": "73bbc993", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -450,7 +450,7 @@ }, { "cell_type": "markdown", - "id": "260971c2", + "id": "34", "metadata": {}, "source": [ "## Abstract Classes\n", @@ -467,7 +467,7 @@ }, { "cell_type": "markdown", - "id": "9aa9f972", + "id": "35", "metadata": {}, "source": [ "We first create an abstract class which inherits from `ABC`:" @@ -476,7 +476,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76974704", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -494,7 +494,7 @@ }, { "cell_type": "markdown", - "id": "0acbe96c", + "id": "37", "metadata": {}, "source": [ "Careful, you **cannot** create an instance of an abstract class!\n", @@ -504,7 +504,7 @@ { "cell_type": "code", "execution_count": null, - "id": "628c6c27", + "id": "38", "metadata": {}, "outputs": [], "source": [ @@ -513,7 +513,7 @@ }, { "cell_type": "markdown", - "id": "b1e4e773", + "id": "39", "metadata": {}, "source": [ "Let's create two concrete subclasses of `Shape`:" @@ -522,7 +522,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8464b677", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -551,7 +551,7 @@ }, { "cell_type": "markdown", - "id": "8461ea5a", + "id": "41", "metadata": {}, "source": [ "Now we are allowed to create instances of the subclasses and also call their methods:" @@ -560,7 +560,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fb964888", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -575,7 +575,7 @@ }, { "cell_type": "markdown", - "id": "e303935f", + "id": "43", "metadata": {}, "source": [ "## Decorators\n", @@ -588,7 +588,7 @@ }, { "cell_type": "markdown", - "id": "bf862978", + "id": "44", "metadata": {}, "source": [ "### @classmethod\n", @@ -602,7 +602,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5124db39", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -641,7 +641,7 @@ }, { "cell_type": "markdown", - "id": "a3b56a04", + "id": "46", "metadata": {}, "source": [ "### @staticmethod\n", @@ -654,7 +654,7 @@ }, { "cell_type": "markdown", - "id": "35296378", + "id": "47", "metadata": {}, "source": [ "As seen in the example below, static methods have limited use, because they don't have access neither to the class attributes nor to any instance of the class.\n", @@ -667,7 +667,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42d50e7e", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -687,7 +687,7 @@ }, { "cell_type": "markdown", - "id": "def0459d", + "id": "49", "metadata": {}, "source": [ "### @property\n", @@ -701,7 +701,7 @@ }, { "cell_type": "markdown", - "id": "5f1db5cd", + "id": "50", "metadata": {}, "source": [ "In this simple example, we create a class `Circle`, which has a radius and an area.\n", @@ -711,7 +711,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d2cdef66", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -733,7 +733,7 @@ }, { "cell_type": "markdown", - "id": "94e64596", + "id": "52", "metadata": {}, "source": [ "We can access the `area` property, just like any other class attribute.\n", @@ -743,7 +743,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b00f4c57", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -752,7 +752,7 @@ }, { "cell_type": "markdown", - "id": "f1f9c5d7", + "id": "54", "metadata": {}, "source": [ "### Setters & Getters\n", @@ -770,7 +770,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b291ac72", + "id": "55", "metadata": {}, "outputs": [], "source": [ @@ -796,7 +796,7 @@ }, { "cell_type": "markdown", - "id": "408a247d", + "id": "56", "metadata": {}, "source": [ "Create an instance and use the getter:" @@ -805,7 +805,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5cc19eca", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -815,7 +815,7 @@ }, { "cell_type": "markdown", - "id": "7ac2c761", + "id": "58", "metadata": {}, "source": [ "Update the radius using the setter:" @@ -824,7 +824,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7879ac76", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -835,7 +835,7 @@ }, { "cell_type": "markdown", - "id": "fdbba2d9", + "id": "60", "metadata": {}, "source": [ "What happens when we enter an invalid value?" @@ -844,7 +844,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ddbebbc8", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -853,7 +853,7 @@ }, { "cell_type": "markdown", - "id": "7d8480a0", + "id": "62", "metadata": {}, "source": [ "Finally let's use the deleter:" @@ -862,7 +862,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4f2baefa", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -871,7 +871,7 @@ }, { "cell_type": "markdown", - "id": "beb6b0a8", + "id": "64", "metadata": {}, "source": [ "We are no longer able to access the deleted attribute:" @@ -880,7 +880,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a9c5335b", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -889,7 +889,7 @@ }, { "cell_type": "markdown", - "id": "cb71df8e", + "id": "66", "metadata": {}, "source": [ "## Encapsulation\n", @@ -923,7 +923,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9f5de760", + "id": "67", "metadata": {}, "outputs": [], "source": [ @@ -941,7 +941,7 @@ }, { "cell_type": "markdown", - "id": "de6dc87b", + "id": "68", "metadata": {}, "source": [ "### Protected\n", @@ -954,7 +954,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0c39a254", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -972,7 +972,7 @@ }, { "cell_type": "markdown", - "id": "8689cbe1", + "id": "70", "metadata": {}, "source": [ "## How to write better classes" @@ -980,7 +980,7 @@ }, { "cell_type": "markdown", - "id": "86330c78", + "id": "71", "metadata": {}, "source": [ "Lastly, we would like to offer some tips & tricks that will help you write your code in a cleaner and easier-to-maintain way." @@ -988,7 +988,7 @@ }, { "cell_type": "markdown", - "id": "7f04e44b", + "id": "72", "metadata": {}, "source": [ "### Using dataclasses\n", @@ -999,7 +999,7 @@ { "cell_type": "code", "execution_count": null, - "id": "eb2c31cd", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -1012,7 +1012,7 @@ }, { "cell_type": "markdown", - "id": "242e2a3a", + "id": "74", "metadata": {}, "source": [ "A simpler way, however, would be to import `dataclass` from the `dataclasses` module.\n", @@ -1025,7 +1025,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d51672e8", + "id": "75", "metadata": {}, "outputs": [], "source": [ @@ -1040,7 +1040,7 @@ }, { "cell_type": "markdown", - "id": "98c63219", + "id": "76", "metadata": {}, "source": [ "Now, with the use of these auto generated methods, we can create an instance of the class and print a representation of the object, without any additional code.\n", @@ -1050,7 +1050,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b6b9c9f4", + "id": "77", "metadata": {}, "outputs": [], "source": [ @@ -1064,7 +1064,7 @@ }, { "cell_type": "markdown", - "id": "7de0eaee", + "id": "78", "metadata": {}, "source": [ "### Using attrs\n", @@ -1077,7 +1077,7 @@ }, { "cell_type": "markdown", - "id": "6653a90f", + "id": "79", "metadata": {}, "source": [ "Let's rewrite the previous example, this time using `attrs`.\n", @@ -1087,7 +1087,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3542eecd", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -1109,7 +1109,7 @@ }, { "cell_type": "markdown", - "id": "e43f026b", + "id": "81", "metadata": {}, "source": [ "However, `attrs` also provides **validators**.\n", @@ -1121,7 +1121,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4126beb3", + "id": "82", "metadata": {}, "outputs": [], "source": [ @@ -1143,7 +1143,7 @@ }, { "cell_type": "markdown", - "id": "fd7fe5aa", + "id": "83", "metadata": {}, "source": [ "## Quiz\n", @@ -1154,7 +1154,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0e3939dc", + "id": "84", "metadata": {}, "outputs": [], "source": [ @@ -1165,7 +1165,7 @@ }, { "cell_type": "markdown", - "id": "48b8fb9d", + "id": "85", "metadata": {}, "source": [ "## Exercises" @@ -1174,7 +1174,7 @@ { "cell_type": "code", "execution_count": null, - "id": "78bd3344", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -1183,7 +1183,7 @@ }, { "cell_type": "markdown", - "id": "f412cbcf", + "id": "87", "metadata": {}, "source": [ "### Child Eye Color\n", @@ -1208,7 +1208,7 @@ { "cell_type": "code", "execution_count": null, - "id": "95e9adda", + "id": "88", "metadata": {}, "outputs": [], "source": [ @@ -1226,7 +1226,7 @@ }, { "cell_type": "markdown", - "id": "21f988cd", + "id": "89", "metadata": {}, "source": [ "### Store Inventory\n", @@ -1265,7 +1265,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ff14680d", + "id": "90", "metadata": {}, "outputs": [], "source": [ @@ -1296,7 +1296,7 @@ }, { "cell_type": "markdown", - "id": "b7d13ea2", + "id": "91", "metadata": {}, "source": [ "### Music Streaming Service\n", @@ -1324,7 +1324,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b1a6ef37", + "id": "92", "metadata": {}, "outputs": [], "source": [ @@ -1355,7 +1355,7 @@ }, { "cell_type": "markdown", - "id": "eaf27dd7", + "id": "93", "metadata": {}, "source": [ "### Banking System\n", @@ -1412,7 +1412,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e516b259", + "id": "94", "metadata": {}, "outputs": [], "source": [ @@ -1427,7 +1427,7 @@ }, { "cell_type": "markdown", - "id": "8c5e7c07-7983-4934-b44e-68251f79c849", + "id": "95", "metadata": {}, "source": [ "### The N-body problem" @@ -1435,7 +1435,7 @@ }, { "cell_type": "markdown", - "id": "a09068a5-cea9-4a0d-8984-89afec13bb19", + "id": "96", "metadata": {}, "source": [ "On a boring and rainy Sunday afternoon, you decide that you want to attempt writing a Python program that simulates the orbits of Jupiter's moons. To start with, you decide to focus your efforts on tracking just **four** of the largest moons: Io, Europa, Ganymede, and Callisto.\n", @@ -1456,7 +1456,7 @@ }, { "cell_type": "markdown", - "id": "3a95b55b-18b0-42ee-b935-c906525e956f", + "id": "97", "metadata": {}, "source": [ "
\n", @@ -1468,7 +1468,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c6ea83f7-9418-4c51-8edf-b980ed29a305", + "id": "98", "metadata": { "tags": [] }, @@ -1481,7 +1481,7 @@ }, { "cell_type": "markdown", - "id": "81387cf7-d457-4187-95e2-71d7bff53204", + "id": "99", "metadata": {}, "source": [ "
\n", @@ -1492,7 +1492,7 @@ }, { "cell_type": "markdown", - "id": "d8ae642a-835c-42bc-872b-30af037ceca9", + "id": "100", "metadata": {}, "source": [ "Each of the strings output by your solution function below should be something like\n", @@ -1506,7 +1506,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16167b86-9230-4be8-a562-bf61b0ec5a97", + "id": "101", "metadata": { "tags": [] }, @@ -1520,7 +1520,7 @@ }, { "cell_type": "markdown", - "id": "9d8483a5-d4ac-49f1-a149-5d0436d36faa", + "id": "102", "metadata": {}, "source": [ "---\n", @@ -1544,7 +1544,7 @@ }, { "cell_type": "markdown", - "id": "35bf40db-3185-4e19-ab45-e46203998aa8", + "id": "103", "metadata": {}, "source": [ "To have a complete account of the moons' orbits, you need to compute the **total energy of the system**. The total energy for a single moon is its **potential energy** multiplied by its **kinetic energy**.\n", @@ -1586,7 +1586,7 @@ }, { "cell_type": "markdown", - "id": "8e33a97d-abfc-449d-827a-295c26804130", + "id": "104", "metadata": {}, "source": [ "
\n", @@ -1598,7 +1598,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8ff18365-2437-41ed-8f7c-811bc719df12", + "id": "105", "metadata": { "tags": [] }, @@ -1611,7 +1611,7 @@ }, { "cell_type": "markdown", - "id": "d091b28d-30b9-401c-bda4-e91ecc2fa290", + "id": "106", "metadata": {}, "source": [ "
\n", @@ -1627,7 +1627,7 @@ }, { "cell_type": "markdown", - "id": "73020f30-3812-4ca0-aa90-8683acfd9a14", + "id": "107", "metadata": {}, "source": [ "
\n", @@ -1639,7 +1639,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a3b0dd72-6fd5-4602-912f-c44deaf6d633", + "id": "108", "metadata": { "tags": [] }, diff --git a/slides/control_flow_slides.ipynb b/slides/control_flow_slides.ipynb index d65651a1..1619f836 100644 --- a/slides/control_flow_slides.ipynb +++ b/slides/control_flow_slides.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "raw", - "id": "e98e8ae2-16df-4e85-9d95-19d6f0f5e24f", + "id": "0", "metadata": {}, "source": [ "---\n", @@ -19,7 +19,7 @@ }, { "cell_type": "markdown", - "id": "7d456e6b-159d-4959-b258-60963c381ff6", + "id": "1", "metadata": {}, "source": [ "# Table of contents {visibility=\"hidden\"}\n", @@ -41,7 +41,7 @@ }, { "cell_type": "markdown", - "id": "5e5bb08a-2045-411b-8792-8cb255e9f066", + "id": "2", "metadata": {}, "source": [ "## References {visibility=\"hidden\"}" @@ -49,7 +49,7 @@ }, { "cell_type": "markdown", - "id": "d79e417f-e04a-4f44-a2da-0759a5f845cf", + "id": "3", "metadata": {}, "source": [ "From \"Python 4 Everybody\" online tutorial:\n", @@ -60,7 +60,7 @@ }, { "cell_type": "markdown", - "id": "74f5fff2-1321-49c3-aaa5-0151bb87fced", + "id": "4", "metadata": { "tags": [] }, @@ -70,7 +70,7 @@ }, { "cell_type": "markdown", - "id": "c77d7858-0f56-4925-9724-689aadbb23a7", + "id": "5", "metadata": {}, "source": [ "Python [supports](./basic_datatypes.ipynb#Comparison-operators) different comparison expressions. They return either `True` or `False`.\n", @@ -80,7 +80,7 @@ }, { "cell_type": "markdown", - "id": "0d1335e1-76e8-48ad-907a-a9b9d14c61a5", + "id": "6", "metadata": {}, "source": [ "---\n", @@ -111,7 +111,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f79d4a60", + "id": "7", "metadata": { "tags": [] }, @@ -144,7 +144,7 @@ }, { "cell_type": "markdown", - "id": "086bd853-ed18-4d16-8a34-44675faa860c", + "id": "8", "metadata": { "tags": [] }, @@ -154,7 +154,7 @@ }, { "cell_type": "markdown", - "id": "2f047b04-c9c0-49b3-8476-f7aa31a45bb6", + "id": "9", "metadata": {}, "source": [ "`while` loops repeat a block of code until some condition remains true.\n", @@ -177,7 +177,7 @@ }, { "cell_type": "markdown", - "id": "6d6d18f4-a797-4a3a-acd7-76a5e3d29f8c", + "id": "10", "metadata": {}, "source": [ "A very simple example:" @@ -186,7 +186,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2d7f000c-6b7a-44e8-bc96-0fe677ceeea3", + "id": "11", "metadata": { "tags": [] }, @@ -202,7 +202,7 @@ }, { "cell_type": "markdown", - "id": "7d975ebe", + "id": "12", "metadata": {}, "source": [ "First, `n` is initialized to 1.\n", @@ -215,7 +215,7 @@ }, { "cell_type": "markdown", - "id": "8e5c5a4d-3a5d-43ad-a5dc-abb53799b71d", + "id": "13", "metadata": {}, "source": [ "\n", @@ -247,7 +247,7 @@ }, { "cell_type": "markdown", - "id": "96aaf8c7-3c4b-4547-8f62-cf49f840159b", + "id": "14", "metadata": { "tags": [] }, @@ -257,7 +257,7 @@ }, { "cell_type": "markdown", - "id": "2b2eac3c-c83d-482b-975b-7b7787206310", + "id": "15", "metadata": {}, "source": [ "In Python, an **iterable** is an **object** capable of returning its members one at a time.\n", @@ -276,7 +276,7 @@ }, { "cell_type": "markdown", - "id": "fd11a026-1d83-437c-8a41-263ed76ed764", + "id": "16", "metadata": {}, "source": [ "In other languages (C++, Java or JavaScript), a `for` loop is more similar to `while` in Python. For example, the C++ loop\n", @@ -316,7 +316,7 @@ }, { "cell_type": "markdown", - "id": "ea4aa10a-f4f3-4d8f-ac61-f1fc20237a46", + "id": "17", "metadata": {}, "source": [ "---\n", @@ -327,7 +327,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9ca56906-4c43-4d0c-acf6-07a1370299d9", + "id": "18", "metadata": { "tags": [] }, @@ -339,7 +339,7 @@ }, { "cell_type": "markdown", - "id": "bcf00919-de04-4406-8c9a-5ee9b80a0623", + "id": "19", "metadata": {}, "source": [ "The loops runs until there are letters in the string `'Python'`, as strings are iterable.\n", @@ -349,7 +349,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4c97b210-1fa9-4d73-b156-5306e0b9c256", + "id": "20", "metadata": { "tags": [] }, @@ -365,7 +365,7 @@ }, { "cell_type": "markdown", - "id": "e3f2fdf7-d032-4c69-975c-704acae75ade", + "id": "21", "metadata": {}, "source": [ "Why writing six lines of code when we can do the same with just two?" @@ -373,7 +373,7 @@ }, { "cell_type": "markdown", - "id": "75cb8fcd-6cb7-4c04-a843-3369eb41e066", + "id": "22", "metadata": {}, "source": [ "---\n", @@ -394,7 +394,7 @@ }, { "cell_type": "markdown", - "id": "642d0ffe-b8c9-4076-a2e2-1b86722cf1a1", + "id": "23", "metadata": { "tags": [] }, @@ -404,7 +404,7 @@ }, { "cell_type": "markdown", - "id": "840b0480-9cc7-4947-8cf9-c375d9d267f5", + "id": "24", "metadata": { "jp-MarkdownHeadingCollapsed": true, "tags": [] @@ -437,7 +437,7 @@ }, { "cell_type": "markdown", - "id": "c460c1d8-54c9-48cc-bf35-3395c78214fc", + "id": "25", "metadata": { "tags": [] }, @@ -447,7 +447,7 @@ }, { "cell_type": "markdown", - "id": "03709197-8bbc-4ba8-9f96-5e380ccc4484", + "id": "26", "metadata": {}, "source": [ "There are **4 ways** in which you can alter the normal execution of a loop:\n", @@ -460,7 +460,7 @@ }, { "cell_type": "markdown", - "id": "3fe08146-d503-4595-b031-ca765e8b3e77", + "id": "27", "metadata": {}, "source": [ "---\n", @@ -473,7 +473,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33c2bc7a-130a-40ef-8f9a-07eab5aa9283", + "id": "28", "metadata": { "tags": [] }, @@ -492,7 +492,7 @@ }, { "cell_type": "markdown", - "id": "9211f675-0cda-449e-bcd4-0fa3d4c2f3a8", + "id": "29", "metadata": {}, "source": [ "---\n", @@ -505,7 +505,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b3ff6863-2dff-4dfb-a6f0-8d91f1801476", + "id": "30", "metadata": { "tags": [] }, @@ -523,7 +523,7 @@ }, { "cell_type": "markdown", - "id": "0e9e96a9-b55e-4862-9843-5dc8364f3673", + "id": "31", "metadata": {}, "source": [ "---\n", @@ -536,7 +536,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3cba31f4-4242-476d-a646-507e3e85fc1a", + "id": "32", "metadata": { "tags": [] }, @@ -552,7 +552,7 @@ }, { "cell_type": "markdown", - "id": "7076fd6d-524e-45b4-873e-ec86d5847e27", + "id": "33", "metadata": {}, "source": [ "---\n", @@ -567,7 +567,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d62ea1e6-9e05-41c1-85aa-5c5970fc6b85", + "id": "34", "metadata": { "tags": [] }, @@ -585,7 +585,7 @@ }, { "cell_type": "markdown", - "id": "c9ea4715", + "id": "35", "metadata": {}, "source": [ "Let's see what happens if we change the list to `[1, 2, 3, 4]`:" @@ -594,7 +594,7 @@ { "cell_type": "code", "execution_count": null, - "id": "71be2a81", + "id": "36", "metadata": { "tags": [] }, @@ -612,7 +612,7 @@ }, { "cell_type": "markdown", - "id": "478550ff-87ad-45f5-adcb-1f486bfb5689", + "id": "37", "metadata": {}, "source": [ "## Exceptions" @@ -620,7 +620,7 @@ }, { "cell_type": "markdown", - "id": "d192308f-eb06-4b39-b791-8df6514ca491", + "id": "38", "metadata": {}, "source": [ "Another way of controlling the flow of a program is by **catching exceptions**.\n", @@ -660,7 +660,7 @@ }, { "cell_type": "markdown", - "id": "542fdbf1-d9e5-4f71-baac-e66899c99292", + "id": "39", "metadata": {}, "source": [ "## The `try-except` block" @@ -668,7 +668,7 @@ }, { "cell_type": "markdown", - "id": "5b1e549e-a24d-43b7-9531-e14383f64069", + "id": "40", "metadata": {}, "source": [ "When you can predict if a certain exception might occur, it's **always a good programming practice** to write what the program should do in that case\n", @@ -679,7 +679,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b7dc7edb-9398-4b8f-a0a9-d00a5c50e3f7", + "id": "41", "metadata": { "tags": [] }, @@ -697,7 +697,7 @@ }, { "cell_type": "markdown", - "id": "3c1e6903-4306-4255-907c-8e71dbdcee7b", + "id": "42", "metadata": {}, "source": [ "---\n", @@ -708,7 +708,7 @@ { "cell_type": "code", "execution_count": null, - "id": "d92a4bb9-6844-4633-aad8-33cdac070325", + "id": "43", "metadata": { "tags": [] }, @@ -725,7 +725,7 @@ }, { "cell_type": "markdown", - "id": "11357ea4-ff6d-4831-975b-921f7630d37f", + "id": "44", "metadata": {}, "source": [ "Or you can **catch each exceptions individually** to give more information about the kind of error encountered\n", @@ -751,7 +751,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5fc9d098-e17f-4ddd-8f32-7e33651d2052", + "id": "45", "metadata": { "tags": [] }, @@ -770,7 +770,7 @@ }, { "cell_type": "markdown", - "id": "295c7eb8-9c74-43f9-ae5c-58e6699d90e6", + "id": "46", "metadata": {}, "source": [ "- We try to open a file called `README.txt`. A `FileNotFoundError` will be raised if it's not found\n", @@ -786,7 +786,7 @@ }, { "cell_type": "markdown", - "id": "3175d392-66b2-4bca-80f9-cf3f45c3a84a", + "id": "47", "metadata": { "tags": [] }, @@ -797,7 +797,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b834570f-965c-4440-9c6e-d713f680c82b", + "id": "48", "metadata": { "tags": [] }, @@ -810,7 +810,7 @@ }, { "cell_type": "markdown", - "id": "26f986e9-dd0e-4445-b6df-73aee64c565b", + "id": "49", "metadata": { "tags": [] }, @@ -820,7 +820,7 @@ }, { "cell_type": "markdown", - "id": "c596ee74-776e-4114-b82c-823fc9f8f751", + "id": "50", "metadata": {}, "source": [ "A factor of a positive integer `n` is any positive integer less than or equal to `n` that divides `n` with no remainder.\n", @@ -833,7 +833,7 @@ { "cell_type": "code", "execution_count": null, - "id": "4b18485d-ad65-4388-813b-b37832ef255e", + "id": "51", "metadata": { "tags": [] }, @@ -850,7 +850,7 @@ }, { "cell_type": "markdown", - "id": "5c2e26a7-31f4-4419-a68d-811da56adfb1", + "id": "52", "metadata": {}, "source": [ "## Find the pair 🌶️\n", @@ -864,7 +864,7 @@ }, { "cell_type": "markdown", - "id": "4156c367-e1b8-400c-bb2f-71c812c8ee7a", + "id": "53", "metadata": {}, "source": [ "### Part 1" @@ -873,7 +873,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54360e0e-0867-4acc-8f48-35ca15b37d39", + "id": "54", "metadata": { "tags": [] }, @@ -890,7 +890,7 @@ }, { "cell_type": "markdown", - "id": "55055676-4a91-4c45-8db6-b1736a958138", + "id": "55", "metadata": {}, "source": [ "### Part 2\n", @@ -903,7 +903,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ae7e92dd-caa2-41ea-9eda-ad2d7a2bf1ad", + "id": "56", "metadata": { "tags": [] }, @@ -920,7 +920,7 @@ }, { "cell_type": "markdown", - "id": "cc5d1993-29ab-4e73-911f-61830a220c4e", + "id": "57", "metadata": {}, "source": [ "## Cats with hats 🌶️🌶️\n", @@ -943,7 +943,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a694a2c2-38de-4576-964e-cc3181d9fa0d", + "id": "58", "metadata": { "tags": [] }, @@ -960,7 +960,7 @@ }, { "cell_type": "markdown", - "id": "ef9ce337-7a8b-4766-9593-28edf579fe25", + "id": "59", "metadata": { "tags": [] }, @@ -970,7 +970,7 @@ }, { "cell_type": "markdown", - "id": "ef18383f-235f-420f-9f48-f7de45c94d28", + "id": "60", "metadata": {}, "source": [ "During a winter holidays break, your friends propose to hold a [toboggan](https://en.wikipedia.org/wiki/Toboggan) race. While inspecting the map of the place where you decided to hold the race, you realize that it could be rather dangerous as there are many trees along the slope.\n", @@ -998,7 +998,7 @@ }, { "cell_type": "markdown", - "id": "3a4a6a1e-79d0-4ac1-9821-a134dea56b19", + "id": "61", "metadata": {}, "source": [ "#### Part 1 🌶️" @@ -1006,7 +1006,7 @@ }, { "cell_type": "markdown", - "id": "a1b89202-88f3-4758-bffe-c9026ff993d5", + "id": "62", "metadata": {}, "source": [ "Question: How many trees would you encounter during your slope?" @@ -1014,7 +1014,7 @@ }, { "cell_type": "markdown", - "id": "5d5699be-3d72-4e31-9281-456dd5025297", + "id": "63", "metadata": {}, "source": [ "*Hint 1:* Read the trees map as a **nested list** where each `#` corresponds to 1 and each empty site is 0" @@ -1022,7 +1022,7 @@ }, { "cell_type": "markdown", - "id": "6c528a49-5f30-48ae-9fa5-29bd3e6ff4d7", + "id": "64", "metadata": {}, "source": [ "*Hint 2:* In the `solution_` function, define **4 variables**:\n", @@ -1036,7 +1036,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a01ced11-d8df-4dcb-af5a-c31cc507f5b7", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -1074,7 +1074,7 @@ }, { "cell_type": "markdown", - "id": "8ae69510-8756-4c24-b3ec-013fc1c9a621", + "id": "66", "metadata": { "tags": [] }, @@ -1084,7 +1084,7 @@ }, { "cell_type": "markdown", - "id": "d632bbac-f22f-4ede-84db-f8885c27ce30", + "id": "67", "metadata": {}, "source": [ "You check other possible slopes to see if you chose the safest one. These are all the possible slopes according to your map:\n", @@ -1100,7 +1100,7 @@ }, { "cell_type": "markdown", - "id": "c80bdc85-4198-43fc-bf77-bc29406022e8", + "id": "68", "metadata": {}, "source": [ "Hint: Define a variable slopes as a list (or tuple) containing lists (or tuples) of the slopes' steps above" @@ -1109,7 +1109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f39f7b6f-d768-4e8f-ace7-708eee7337a2", + "id": "69", "metadata": {}, "outputs": [], "source": [ diff --git a/slides/functions_slides.ipynb b/slides/functions_slides.ipynb index bb001bc3..7ebbd69e 100644 --- a/slides/functions_slides.ipynb +++ b/slides/functions_slides.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "raw", - "id": "f4700c59-00de-4805-96b8-a7fa6df075b3", + "id": "0", "metadata": {}, "source": [ "---\n", @@ -19,7 +19,7 @@ }, { "cell_type": "markdown", - "id": "c9a51b45-de42-4887-9244-f6cc1d74aa0e", + "id": "1", "metadata": {}, "source": [ "# Table of contents {visibility=\"hidden\"}\n", @@ -53,7 +53,7 @@ }, { "cell_type": "markdown", - "id": "3edb3999-85e2-4cd5-bcfa-67693891bf6f", + "id": "2", "metadata": { "tags": [] }, @@ -63,7 +63,7 @@ }, { "cell_type": "markdown", - "id": "ad4e36dc-2e37-41ca-bc4e-48ea24975fe2", + "id": "3", "metadata": {}, "source": [ "Additional materials where you can find more details about writing functions in Python. For each link, it's indicated if it's a video, a text, or a practical resource.\n", @@ -74,7 +74,7 @@ }, { "cell_type": "markdown", - "id": "00ac8e40-9a6e-4fda-bcd6-ca0b7bb0bfd4", + "id": "4", "metadata": {}, "source": [ "---" @@ -82,7 +82,7 @@ }, { "cell_type": "markdown", - "id": "6787e774-0b23-428a-abe2-b966c1a59047", + "id": "5", "metadata": { "tags": [] }, @@ -100,7 +100,7 @@ }, { "cell_type": "markdown", - "id": "d1e43724-68a1-4fdb-a846-dc1c926d3d4a", + "id": "6", "metadata": {}, "source": [ "1. Functions in Python are blocks of reusable code that perform a specific task.\n", @@ -110,7 +110,7 @@ }, { "cell_type": "markdown", - "id": "d86ccb9a-9544-4db1-a383-e1b1c4f29ee5", + "id": "7", "metadata": { "tags": [] }, @@ -125,7 +125,7 @@ }, { "cell_type": "markdown", - "id": "d97931a5-31fd-494a-8a4a-f62102a6062e", + "id": "8", "metadata": { "tags": [] }, @@ -135,7 +135,7 @@ }, { "cell_type": "markdown", - "id": "2dde8114-7527-49bc-9b2c-de56dd94de9b", + "id": "9", "metadata": {}, "source": [ "A function in Python has three main parts:\n", @@ -147,7 +147,7 @@ }, { "cell_type": "markdown", - "id": "36be5fba-1079-4e48-8115-ce22b10de76e", + "id": "10", "metadata": {}, "source": [ "## Signature\n", @@ -169,7 +169,7 @@ }, { "cell_type": "markdown", - "id": "5579a33e-65d0-4edf-bbc1-14672f6c09a2", + "id": "11", "metadata": {}, "source": [ "---\n", @@ -210,7 +210,7 @@ }, { "cell_type": "markdown", - "id": "e7ef2776-3643-4a44-94fe-6aaa466e5938", + "id": "12", "metadata": {}, "source": [ "## Body\n", @@ -220,7 +220,7 @@ }, { "cell_type": "markdown", - "id": "28265ca7-c247-4040-ad4e-3b1b004542d1", + "id": "13", "metadata": {}, "source": [ "```python\n", @@ -232,7 +232,7 @@ }, { "cell_type": "markdown", - "id": "b40e2fe7-e340-4757-b43c-ee616d7693c8", + "id": "14", "metadata": {}, "source": [ "The function's outputs are indicated by the (reserved) keyword `return`. All functions in Python return a value, even if that value is `None`. If you omit the `return` keyword, Python assumes that the function returns `None`." @@ -240,7 +240,7 @@ }, { "cell_type": "markdown", - "id": "91939086-1d33-43fe-8982-ffbba3d77f07", + "id": "15", "metadata": {}, "source": [ "## Docstrings\n", @@ -277,7 +277,7 @@ }, { "cell_type": "markdown", - "id": "d5358dfc-df7d-4a6f-9f3a-4e06820e271c", + "id": "16", "metadata": { "tags": [] }, @@ -287,7 +287,7 @@ }, { "cell_type": "markdown", - "id": "4939ebe9-1e3a-4ef8-b4a6-7604c7c243ef", + "id": "17", "metadata": {}, "source": [ "The terms **parameters** and **arguments** are often used interchangeably, but they refer to different things in the context of function calls." @@ -295,7 +295,7 @@ }, { "cell_type": "markdown", - "id": "339553d5-4a61-4242-a369-6993dc78dc35", + "id": "18", "metadata": {}, "source": [ "## Parameters\n", @@ -305,7 +305,7 @@ }, { "cell_type": "markdown", - "id": "7f845593-f20f-4941-869e-3a7dcd624e9e", + "id": "19", "metadata": {}, "source": [ "```python\n", @@ -319,7 +319,7 @@ }, { "cell_type": "markdown", - "id": "79168642-bad5-4bd8-b625-1742669b55e4", + "id": "20", "metadata": {}, "source": [ "## Arguments\n", @@ -336,7 +336,7 @@ }, { "cell_type": "markdown", - "id": "5b5cb5f3-504d-4edb-8c84-98ace0127cde", + "id": "21", "metadata": {}, "source": [ "## Positional arguments\n", @@ -358,7 +358,7 @@ }, { "cell_type": "markdown", - "id": "7433d92d-1614-430d-a452-34ad82bdf924", + "id": "22", "metadata": {}, "source": [ "## Keyword arguments\n", @@ -384,7 +384,7 @@ }, { "cell_type": "markdown", - "id": "c3431b9d-705c-4598-80bd-79e590a0d17d", + "id": "23", "metadata": {}, "source": [ "## Default values\n", @@ -407,7 +407,7 @@ { "cell_type": "code", "execution_count": null, - "id": "0807177a-e2f3-412c-a10d-691a1109f591", + "id": "24", "metadata": { "tags": [] }, @@ -424,7 +424,7 @@ }, { "cell_type": "markdown", - "id": "dd593351-58d2-4cab-886e-d7f093445bee", + "id": "25", "metadata": { "tags": [] }, @@ -434,7 +434,7 @@ }, { "cell_type": "markdown", - "id": "d1e150ea-588c-4f4a-88b4-3d2fad1c1ce6", + "id": "26", "metadata": { "tags": [] }, @@ -485,7 +485,7 @@ }, { "cell_type": "markdown", - "id": "04747296-7d42-4f8e-b0e4-705593baad3d", + "id": "27", "metadata": { "tags": [] }, @@ -495,7 +495,7 @@ }, { "cell_type": "markdown", - "id": "7819c88f-5881-41ad-b896-66ce9af404fb", + "id": "28", "metadata": {}, "source": [ "The following might seem trivial: could we assign the same variable name to two different values?\n", @@ -552,7 +552,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7d8a1837-c789-4308-a25f-4d9addc0f1f5", + "id": "29", "metadata": { "tags": [] }, @@ -572,7 +572,7 @@ }, { "cell_type": "markdown", - "id": "2a13e84d-d026-49fc-9a9f-6a0f2be72a69", + "id": "30", "metadata": {}, "source": [ "In this example, `x` is a **global** variable and is accessible from anywhere in the program. `x` is also a **local** variable to the `function`, and is accessible from within the function's body.\n", @@ -582,7 +582,7 @@ }, { "cell_type": "markdown", - "id": "6e18100e-7bca-4fbc-979d-9156fda1dc34", + "id": "31", "metadata": {}, "source": [ "::: {.notes}\n", @@ -598,7 +598,7 @@ }, { "cell_type": "markdown", - "id": "7a33ad56-74b6-4e13-83a4-4301214fceef", + "id": "32", "metadata": {}, "source": [ "Look at the following example:" @@ -606,7 +606,7 @@ }, { "cell_type": "markdown", - "id": "ae5cccb2-356b-4d18-af38-8d07fd2f600a", + "id": "33", "metadata": {}, "source": [ "```{.python code-line-numbers=\"|10-11\"}\n", @@ -634,7 +634,7 @@ }, { "cell_type": "markdown", - "id": "abf76e9a-5a61-4458-87be-a582f44c2774", + "id": "34", "metadata": {}, "source": [ "---\n", @@ -647,7 +647,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fa5a2ab0-3594-41da-8c90-5f378efd34ce", + "id": "35", "metadata": { "tags": [] }, @@ -669,7 +669,7 @@ }, { "cell_type": "markdown", - "id": "e2048b56-9338-4284-96ef-5af250a55eb4", + "id": "36", "metadata": {}, "source": [ "::: {.notes}\n", @@ -683,7 +683,7 @@ }, { "cell_type": "markdown", - "id": "ee1cdfe3-90f0-43ac-852d-01adfc51b60b", + "id": "37", "metadata": {}, "source": [ "# `*args` and `**kwargs`" @@ -691,7 +691,7 @@ }, { "cell_type": "markdown", - "id": "b87faacb-1da9-4e5b-9cd1-0a23d0ce74b8", + "id": "38", "metadata": {}, "source": [ "In the [Basic datatypes](./basic_datatypes.ipynb#Unpacking) section we saw that iterables (tuples and lists) support **unpacking**. You can exploit unpacking to make a **parallel assignment**.\n", @@ -704,7 +704,7 @@ { "cell_type": "code", "execution_count": null, - "id": "7780b91b-c4b1-4213-a8fa-f1802f02df60", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -719,7 +719,7 @@ }, { "cell_type": "markdown", - "id": "349a3646-f40f-4e57-acfa-b9ba01106734", + "id": "40", "metadata": {}, "source": [ "The only difference with unpacking is: all the optional positional arguments are collected by `*args` **in a tuple** and not in a list.\n", @@ -729,7 +729,7 @@ }, { "cell_type": "markdown", - "id": "b0e594f0-8634-4374-b8ea-e1a267ecc126", + "id": "41", "metadata": {}, "source": [ "One importat rule:\n", @@ -753,7 +753,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8f57bff5-86b1-41c5-b4e9-aecf997446ce", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -765,7 +765,7 @@ }, { "cell_type": "markdown", - "id": "2adb773c-38bc-4281-beb6-bc9b1e430ee5", + "id": "43", "metadata": {}, "source": [ "The following **cannot** work\n", @@ -783,7 +783,7 @@ }, { "cell_type": "markdown", - "id": "944a4e00-3a44-4843-946f-94907e985205", + "id": "44", "metadata": {}, "source": [ "Remember that functions' arguments can be either **positional** or **keyword** arguments:" @@ -792,7 +792,7 @@ { "cell_type": "code", "execution_count": null, - "id": "72157f9a-901e-4d05-a968-156ed87c54da", + "id": "45", "metadata": {}, "outputs": [], "source": [ @@ -803,7 +803,7 @@ }, { "cell_type": "markdown", - "id": "29b31a7f-6ad1-484b-984c-e79a3ee7b57a", + "id": "46", "metadata": {}, "source": [ "We can call the function with" @@ -812,7 +812,7 @@ { "cell_type": "code", "execution_count": null, - "id": "641d9390-66aa-417c-b663-0728f9575822", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -825,7 +825,7 @@ }, { "cell_type": "markdown", - "id": "3215c24b-fe0a-4324-9469-eaf9f33270b7", + "id": "48", "metadata": {}, "source": [ "After `*args` there can be **no additional positional arguments** but we might have some (or no) keyword arguments.\n", @@ -836,7 +836,7 @@ { "cell_type": "code", "execution_count": null, - "id": "c1d3e823-f201-40ba-9134-e9a0f15c1e8e", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -854,7 +854,7 @@ }, { "cell_type": "markdown", - "id": "27a6389a-1d83-45cc-b3e1-19d725823f65", + "id": "50", "metadata": {}, "source": [ "Remember: `d` is a **required** keyword argument because we didn't supply a default value in the function definition.\n", @@ -865,7 +865,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a9c49c52-65db-45eb-896a-e1ffa7e49180", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -875,7 +875,7 @@ { "cell_type": "code", "execution_count": null, - "id": "31ed5304-123b-4b82-a43e-3f63377e38d5", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -885,7 +885,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5ff3f27b-6752-4467-8ce5-3c11a56cb270", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -894,7 +894,7 @@ }, { "cell_type": "markdown", - "id": "fb4c8eb2-efdb-48da-be7f-6ab2d08102ec", + "id": "54", "metadata": {}, "source": [ "We can even **omit** mandatory positional arguments\n", @@ -911,7 +911,7 @@ }, { "cell_type": "markdown", - "id": "ae9c9e74-259b-4468-a56a-e1ae1a1debb0", + "id": "55", "metadata": {}, "source": [ "Or we can force **no positional arguments at all**:\n", @@ -926,7 +926,7 @@ }, { "cell_type": "markdown", - "id": "c5e934a2-9201-4e03-be47-e2f908937624", + "id": "56", "metadata": {}, "source": [ "You can see that with iterables unpacking and the two `*`/`**` operators, Python is showing all its versatility when it comes to writing your own function.\n", @@ -936,7 +936,7 @@ }, { "cell_type": "markdown", - "id": "af454573-8da4-4b1c-9b93-24c2a6d511eb", + "id": "57", "metadata": { "tags": [] }, @@ -947,7 +947,7 @@ { "cell_type": "code", "execution_count": null, - "id": "00ac378c-763a-420b-bf4a-d02469e97c98", + "id": "58", "metadata": { "tags": [] }, @@ -959,7 +959,7 @@ }, { "cell_type": "markdown", - "id": "e5615c16-7130-4c05-9081-0a495d7090b2", + "id": "59", "metadata": { "tags": [] }, @@ -969,7 +969,7 @@ }, { "cell_type": "markdown", - "id": "a680c83c-065a-4ae0-bf6f-fb5084d5c560", + "id": "60", "metadata": { "tags": [] }, @@ -992,7 +992,7 @@ { "cell_type": "code", "execution_count": null, - "id": "f6416b66-f094-432b-8589-5e44e0d67388", + "id": "61", "metadata": { "tags": [] }, @@ -1009,7 +1009,7 @@ }, { "cell_type": "markdown", - "id": "ba435a6b-caac-48e2-a0e2-80edabdf1215", + "id": "62", "metadata": {}, "source": [ "### Part 2 (bonus) 🌶️🌶️🌶️\n", @@ -1022,7 +1022,7 @@ { "cell_type": "code", "execution_count": null, - "id": "b6e0ee24-8115-4741-acfe-c2938bb40525", + "id": "63", "metadata": { "tags": [] }, @@ -1039,7 +1039,7 @@ }, { "cell_type": "markdown", - "id": "1c93c572-7890-4bd7-a0f6-d4015679df39", + "id": "64", "metadata": { "tags": [] }, @@ -1049,7 +1049,7 @@ }, { "cell_type": "markdown", - "id": "6a40b25b-fa38-44c8-8a80-d1e86c38ecab", + "id": "65", "metadata": { "tags": [] }, @@ -1059,7 +1059,7 @@ }, { "cell_type": "markdown", - "id": "61fdaa6e-9f5c-4039-a09e-e79146175703", + "id": "66", "metadata": {}, "source": [ "You have a range of numbers `136760-595730` and need to count how many valid password it contains. A valid password must meet **all** the following criteria:\n", @@ -1088,7 +1088,7 @@ { "cell_type": "code", "execution_count": null, - "id": "517f4d43-0ffa-407d-9035-7c8e47b64103", + "id": "67", "metadata": {}, "outputs": [], "source": [ @@ -1103,7 +1103,7 @@ }, { "cell_type": "markdown", - "id": "edac5c6a-23fa-4f09-a462-5682201a449f", + "id": "68", "metadata": { "tags": [] }, @@ -1115,7 +1115,7 @@ }, { "cell_type": "markdown", - "id": "af330663-15c2-48f7-b407-e09cecc62d4d", + "id": "69", "metadata": {}, "source": [ "You have a new rule: **at least** two adjacent matching digits **must not be part of a larger group of matching digits**.\n", @@ -1136,7 +1136,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17106c0f-e9df-4888-bb21-e2806cc72df4", + "id": "70", "metadata": {}, "outputs": [], "source": [ @@ -1151,7 +1151,7 @@ }, { "cell_type": "markdown", - "id": "503a18e5-8ee4-4a02-89f9-09cbca3a8e50", + "id": "71", "metadata": { "tags": [] }, @@ -1161,7 +1161,7 @@ }, { "cell_type": "markdown", - "id": "957eb5a0-5331-48e3-86b6-7b99299d710f", + "id": "72", "metadata": {}, "source": [ "### Part 1 🌶️" @@ -1169,7 +1169,7 @@ }, { "cell_type": "markdown", - "id": "59093ed8-b422-4f97-8ffc-801f6149458a", + "id": "73", "metadata": {}, "source": [ "You have a list of buckets, each containing some items labeled from `a` to `z`, or from `A` to `Z`. Each bucket is split into **two** equally sized compartments.\n", @@ -1212,7 +1212,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3eea5fd5-fef2-41ef-93fd-541a332cf679", + "id": "74", "metadata": { "tags": [] }, @@ -1228,7 +1228,7 @@ }, { "cell_type": "markdown", - "id": "1085e791-f1df-4fce-89ae-9c169dbf8aa2", + "id": "75", "metadata": {}, "source": [ "### Part 2 🌶️🌶️" @@ -1236,7 +1236,7 @@ }, { "cell_type": "markdown", - "id": "0b68ba01-1a08-43c5-84b2-e73315ab0f53", + "id": "76", "metadata": {}, "source": [ "You are told that you should not care about the priority of **every item**, but only of a \"special item\" that is common to groups of **three buckets**.\n", @@ -1263,7 +1263,7 @@ { "cell_type": "code", "execution_count": null, - "id": "5acf6617-1275-42a0-b656-bfa59d33493b", + "id": "77", "metadata": {}, "outputs": [], "source": [ diff --git a/tutorial/library_pandas_solutions.ipynb b/tutorial/library_pandas_solutions.ipynb index 6b4e3bfb..30eed8f4 100644 --- a/tutorial/library_pandas_solutions.ipynb +++ b/tutorial/library_pandas_solutions.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "0fc7fa8d-1088-4932-80bf-75066e9a15e8", + "id": "0", "metadata": {}, "source": [ "# Solutions to Pandas exercises" @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "c122d454-6d0b-4187-92f5-63fdddcdc4a0", + "id": "1", "metadata": {}, "source": [ "This notebook contains the solutions to some exercises about Pandas that didn't (or couldn't) have a test.\n", @@ -20,7 +20,7 @@ { "cell_type": "code", "execution_count": null, - "id": "61a49949-88a6-455a-a6f4-08dc9cb35b33", + "id": "2", "metadata": {}, "outputs": [], "source": [ @@ -29,7 +29,7 @@ }, { "cell_type": "markdown", - "id": "a31d2921-451d-496e-8f06-fa711452c054", + "id": "3", "metadata": {}, "source": [ "## Working with Pandas `DataFrame`" @@ -37,7 +37,7 @@ }, { "cell_type": "markdown", - "id": "b0e608f7-9a6d-4888-b0e0-b989b7ee81ad", + "id": "4", "metadata": {}, "source": [ "A test is provided for each exercise in this section.\n", @@ -46,7 +46,7 @@ }, { "cell_type": "markdown", - "id": "b1dbbbe4-9eab-4e4e-b2b3-97dbaa3ee28f", + "id": "5", "metadata": {}, "source": [ "## Data wrangling" @@ -54,7 +54,7 @@ }, { "cell_type": "markdown", - "id": "6f2dc6b3-d7ec-4a15-af7b-f5e64381fb12", + "id": "6", "metadata": {}, "source": [ "### Exercise 1" @@ -63,7 +63,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ef099fce-febd-4e48-ab2e-484d2f756e89", + "id": "7", "metadata": {}, "outputs": [], "source": [ @@ -86,7 +86,7 @@ }, { "cell_type": "markdown", - "id": "f8fe414c-93d9-4e97-83ed-a70d060d67af", + "id": "8", "metadata": {}, "source": [ "### Exercise 2" @@ -95,7 +95,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1cae5b90-a5ea-432c-b11f-65bcfd38bc80", + "id": "9", "metadata": {}, "outputs": [], "source": [ @@ -111,7 +111,7 @@ }, { "cell_type": "markdown", - "id": "aa21633f-a156-4781-ad13-7db319e7ae59", + "id": "10", "metadata": {}, "source": [ "### Exercise 3" @@ -120,7 +120,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ed0759ac-baaf-4135-9fab-4713c1d48dab", + "id": "11", "metadata": {}, "outputs": [], "source": [ @@ -129,7 +129,7 @@ }, { "cell_type": "markdown", - "id": "c42b7b49-bebd-413b-a878-a2c57c8d352b", + "id": "12", "metadata": {}, "source": [ "## Data aggregation" @@ -138,7 +138,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17813420-7d21-4a15-b15e-712d5db25ad1", + "id": "13", "metadata": {}, "outputs": [], "source": [ @@ -151,7 +151,7 @@ }, { "cell_type": "markdown", - "id": "4430c9c8-ca6b-46af-b7a9-10fb6c6cbc35", + "id": "14", "metadata": {}, "source": [ "### Exercise 1" @@ -160,7 +160,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56e4f185-ab03-4b72-8541-e227405c1dc2", + "id": "15", "metadata": {}, "outputs": [], "source": [ @@ -171,7 +171,7 @@ }, { "cell_type": "markdown", - "id": "ca06b857-4116-4428-9efb-b11298695316", + "id": "16", "metadata": {}, "source": [ "### Exercise 2" @@ -180,7 +180,7 @@ { "cell_type": "code", "execution_count": null, - "id": "218b724c-7482-4f31-9c58-6fd0f5ab5b5d", + "id": "17", "metadata": {}, "outputs": [], "source": [ @@ -191,7 +191,7 @@ }, { "cell_type": "markdown", - "id": "8243a990-da2f-4dbc-b096-2c29bc68f861", + "id": "18", "metadata": {}, "source": [ "### Exercise 3" @@ -199,7 +199,7 @@ }, { "cell_type": "markdown", - "id": "d65fd016-9710-401c-b457-27338a1276ec", + "id": "19", "metadata": {}, "source": [ "***Note:** we replaced the aggregation operators (or callbacks) `np.mean`, `np.max`, etc. with their string equivalents. This is because explicit callbacks are deprecated in Pandas.*" @@ -208,7 +208,7 @@ { "cell_type": "code", "execution_count": null, - "id": "2b42a50c-c12f-4699-85d5-0774ca943026", + "id": "20", "metadata": {}, "outputs": [], "source": [ diff --git a/tutorial/object_oriented_programming.py b/tutorial/object_oriented_programming.py new file mode 100644 index 00000000..8b9f1d2e --- /dev/null +++ b/tutorial/object_oriented_programming.py @@ -0,0 +1,42 @@ +from .common import Question, Quiz + + +class OopQuiz(Quiz): + def __init__(self, title=""): + q1 = Question( + question="Based on what you learned about Python's special methods, which of the following statements is true?", + options={ + "__repr__ is also used for __str__, but not vice versa.": "Correct! This statement is true.", + "__str__ is also used for __repr__, but not vice versa.": "The opposite is true.", + "__repr__ and __str__ are completely independent.": "__repr__ is also used for __str__, but not vice versa.", + }, + correct_answer="__repr__ is also used for __str__, but not vice versa.", + hint="", + shuffle=True, + ) + + q2 = Question( + question="Based on what you learned about Python's comparison methods, which of the following statements is false?", + options={ + "If we implement __gt__, Python will also use it for __lt__": "This statement is true.", + "If we implement __lt__, Python will also use it for __le__": "Correct! This statement is false.", + "If we implement __eq__, Python will also use it for __ne__": "This statement is true.", + }, + correct_answer="If we implement __lt__, Python will also use it for __le__", + hint="", + shuffle=True, + ) + + q3 = Question( + question="Based on what you learned about the @property keyword, which of the following statements is false?", + options={ + "@property creates attributes that act like methods but can be accessed and assigned as regular attributes.": "This statement is true.", + "@property helps implement attributes that require additional logic or validation when getting or setting their values.": "This statement is true.", + "@property makes code more readable but restricts dynamic attibute behaviour.": "Correct! This statement is false.", + }, + correct_answer="@property makes code more readable but restricts dynamic attibute behaviour.", + hint="", + shuffle=True, + ) + + super().__init__(questions=[q1, q2, q3]) diff --git a/tutorial/tests/test_library_scipy.py b/tutorial/tests/test_library_scipy.py index cf16784d..8c34f3ac 100644 --- a/tutorial/tests/test_library_scipy.py +++ b/tutorial/tests/test_library_scipy.py @@ -147,9 +147,7 @@ def f(y, x): # 2. TODO: define the upper and lower limits: # 3. TODO: call the dblquad function here: - result, error = dblquad( - func=f, a=0, b=2, gfun=lambda x: x, hfun=lambda x: 6 - x**2 - ) + result, error = dblquad(func=f, a=0, b=2, gfun=lambda x: x, hfun=lambda x: 6 - x**2) # 4. TODO: return the result and the error in this order here: return result, error diff --git a/tutorial/tests/test_object_oriented_programming.py b/tutorial/tests/test_object_oriented_programming.py index d832861d..4b8c461c 100644 --- a/tutorial/tests/test_object_oriented_programming.py +++ b/tutorial/tests/test_object_oriented_programming.py @@ -1,93 +1,179 @@ -import pathlib - -import pytest - -# -# Exercise 1: Ice cream scoop -# - - -class Scoop: - """A class representing a single scoop of ice cream""" - - def __init__(self, flavor: str): - self.flavor = flavor - - def __str__(self): - return f"Ice cream scoop with flavor '{self.flavor}'" - - -def test_ice_cream_scoop(function_to_test) -> None: - flavors = ("chocolate", "vanilla", "persimmon") - assert function_to_test(flavors) == [str(Scoop(flavor)) for flavor in flavors] - - -# -# Exercise 2: Ice cream bowl -# - - -class Bowl: - """A class representing a bowl of ice cream scoops""" - - def __init__(self): - self.scoops = [] - - def add_scoops(self, *new_scoops: "Scoop") -> None: - for one_scoop in new_scoops: - self.scoops.append(one_scoop) - - def __str__(self): - return f"Ice cream bowl with {', '.join(s.flavor for s in self.scoops)} scoops" - - -def test_ice_cream_bowl(function_to_test) -> None: - flavors = ("chocolate", "vanilla", "stracciatella") - bowl = Bowl() - scoops = [Scoop(flavor) for flavor in flavors] - bowl.add_scoops(*scoops) - assert function_to_test(flavors) == str(bowl) - - -# -# Exercise 3: Intcode computer -# - - -def read_data(name: str, data_dir: str = "data") -> pathlib.Path: - """Read input data""" - return (pathlib.Path(__file__).parent / f"{data_dir}/{name}").resolve() - - -class Computer: - """An Intcode computer class""" - - def __init__(self, program: str): - self.program = [int(c.strip()) for c in program.split(",")] - self._backup = self.program[:] - - def reset(self): - self.program = self._backup[:] - - def run(self, pos=0): - while True: - if self.program[pos] == 99: - break - op1, op2 = ( - self.program[self.program[pos + 1]], - self.program[self.program[pos + 2]], - ) - func = self.program[pos] - self.program[self.program[pos + 3]] = op1 + op2 if func == 1 else op1 * op2 - pos += 4 - - -intcodes = ["1,0,0,0,99", "2,3,0,3,99", "1,1,1,4,99,5,6,0,99"] -intcodes += [read_data(f"intcode_{i}.txt").read_text() for i in (1, 2)] - - -@pytest.mark.parametrize("intcode", intcodes) -def test_intcode_computer(intcode: str, function_to_test) -> None: - computer = Computer(intcode) - computer.run() - assert function_to_test(intcode) == computer.program[0] +import pathlib + +import pytest + +# +# Exercise 1: Ice cream scoop +# + + +def reference_ice_cream_scoop(flavors: tuple[str]) -> list[str]: + class Scoop: + """A class representing a single scoop of ice cream""" + + def __init__(self, flavor: str): + self.flavor = flavor + + def __str__(self): + return f"Ice cream scoop with flavor '{self.flavor}'" + + return [str(Scoop(flavor)) for flavor in flavors] + + +@pytest.mark.parametrize( + "flavors", + [ + ("chocolate", "vanilla", "persimmon"), + ], +) +def test_ice_cream_scoop(flavors, function_to_test) -> None: + assert function_to_test(flavors) == reference_ice_cream_scoop(flavors) + + +# +# Exercise 2: Ice cream bowl +# + + +def reference_ice_cream_bowl(flavors: tuple[str]) -> str: + class Scoop: + """A class representing a single scoop of ice cream""" + + def __init__(self, flavor: str): + self.flavor = flavor + + def __str__(self): + return f"Ice cream scoop with flavor '{self.flavor}'" + + class Bowl: + """A class representing a bowl of ice cream scoops""" + + def __init__(self): + self.scoops = [] + + def add_scoops(self, *new_scoops: "Scoop") -> None: + for one_scoop in new_scoops: + self.scoops.append(one_scoop) + + def __str__(self): + return ( + f"Ice cream bowl with {', '.join(s.flavor for s in self.scoops)} scoops" + ) + + bowl = Bowl() + scoops = [Scoop(flavor) for flavor in flavors] + bowl.add_scoops(*scoops) + return str(bowl) + + +@pytest.mark.parametrize( + "flavors", + [ + ("chocolate", "vanilla", "stracciatella"), + ], +) +def test_ice_cream_bowl(flavors, function_to_test) -> None: + assert function_to_test(flavors) == reference_ice_cream_bowl(flavors) + + +# +# Exercise 3: Ice cream shop +# + + +def reference_ice_cream_shop(flavors_1: list[str], flavors_2: list[str]) -> bool: + class Shop: + """A class representing an ice cream shop""" + + def __init__(self, flavors): + self.flavors = flavors + + def __str__(self): + return ( + f"Ice cream shop selling flavors: {', '.join(f for f in self.flavors)}" + ) + + def __eq__(self, other): + if isinstance(other, Shop): + return len(self.flavors) == len(other.flavors) + return False + + def __lt__(self, other): + if isinstance(other, Shop): + return len(self.flavors) < len(other.flavors) + return False + + def __le__(self, other): + if isinstance(other, Shop): + return self < other or self == other + return False + + shop_1 = Shop(flavors_1) + shop_2 = Shop(flavors_2) + return shop_1 <= shop_2 + + +@pytest.mark.parametrize( + "flavors_1, flavors_2", + [ + (["chocolate", "vanilla", "stracciatella"], ["caramel", "strawberry", "mango"]), + (["vanilla", "stracciatella"], ["chocolate", "vanilla", "mango"]), + (["vanilla", "mango"], ["chocolate"]), + ], +) +def test_ice_cream_shop(flavors_1, flavors_2, function_to_test) -> None: + assert function_to_test(flavors_1, flavors_2) == reference_ice_cream_shop( + flavors_1, flavors_2 + ) + + +# +# Exercise 4: Intcode computer +# + + +def read_data(name: str, data_dir: str = "data") -> pathlib.Path: + """Read input data""" + return (pathlib.Path(__file__).parent / f"{data_dir}/{name}").resolve() + + +def prepare_params() -> list[str]: + """Prepare input values for a parametrized test""" + intcodes = ["1,0,0,0,99", "2,3,0,3,99", "1,1,1,4,99,5,6,0,99"] + intcodes += [read_data(f"intcode_{i}.txt").read_text() for i in (1, 2)] + return intcodes + + +def reference_intcode_computer(intcode: str) -> int: + class Computer: + """An Intcode computer class""" + + def __init__(self, program: str): + self.program = [int(c.strip()) for c in program.split(",")] + self._backup = self.program[:] + + def run(self, pos=0): + while True: + if self.program[pos] == 99: + break + op1, op2 = ( + self.program[self.program[pos + 1]], + self.program[self.program[pos + 2]], + ) + func = self.program[pos] + self.program[self.program[pos + 3]] = ( + op1 + op2 if func == 1 else op1 * op2 + ) + pos += 4 + + computer = Computer(intcode) + computer.run() + return computer.program[0] + + +@pytest.mark.parametrize( + "intcode", + prepare_params(), +) +def test_intcode_computer(intcode: str, function_to_test) -> None: + assert function_to_test(intcode) == reference_intcode_computer(intcode) diff --git a/tutorial/tests/testsuite/helpers.py b/tutorial/tests/testsuite/helpers.py index b4eec49f..d97a0702 100644 --- a/tutorial/tests/testsuite/helpers.py +++ b/tutorial/tests/testsuite/helpers.py @@ -188,7 +188,11 @@ def prepare_output_cell(self) -> ipywidgets.Output: ) match self.ipytest_result.status: - case IPytestOutcome.COMPILE_ERROR | IPytestOutcome.PYTEST_ERROR | IPytestOutcome.UNKNOWN_ERROR: + case ( + IPytestOutcome.COMPILE_ERROR + | IPytestOutcome.PYTEST_ERROR + | IPytestOutcome.UNKNOWN_ERROR + ): # We know that there is exactly one exception assert self.ipytest_result.exceptions is not None exception = self.ipytest_result.exceptions[0] @@ -282,9 +286,11 @@ def prepare_output_cell(self) -> ipywidgets.Output: HTML( f'

{"✔" if test_succeded else "❌"} Test {test_name}

', style={ - "background": "rgba(251, 59, 59, 0.25)" - if not test_succeded - else "rgba(207, 249, 179, 0.60)" + "background": ( + "rgba(251, 59, 59, 0.25)" + if not test_succeded + else "rgba(207, 249, 179, 0.60)" + ) }, ) ] diff --git a/tutorial/tests/testsuite/testsuite.py b/tutorial/tests/testsuite/testsuite.py index eedbdc46..95290998 100644 --- a/tutorial/tests/testsuite/testsuite.py +++ b/tutorial/tests/testsuite/testsuite.py @@ -1,4 +1,5 @@ """A module to define the `%%ipytest` cell magic""" + import dataclasses import inspect import io