From 42567edc9b465e781a8129f9b294b93ed22b8826 Mon Sep 17 00:00:00 2001 From: Samantha Finnigan <1038320+sjmf@users.noreply.github.com> Date: Wed, 25 Feb 2026 17:01:05 +0000 Subject: [PATCH 1/9] Re-order boolean logic into conditionals (and add truth tables) --- Intermediate.ipynb | 375 ++++++++++++++++++++---------------- Intermediate_full.ipynb | 411 +++++++++++++++++++++------------------- 2 files changed, 430 insertions(+), 356 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index 32e64a0..b83adf6 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -678,164 +678,6 @@ "print(\"Exponentiation:\", 2 ** 3)" ] }, - { - "cell_type": "markdown", - "id": "9ca15865", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "#### Boolean" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7b7abb8", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "b1 = False\n", - "b2 = True\n", - "print(b1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9296bb88", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "type(True) # boolean" - ] - }, - { - "cell_type": "markdown", - "id": "eae67d96", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "**Logical Operators** \n", - "We can also determine conditions based on Boolean logic: `and`, `or`, `not`" - ] - }, - { - "cell_type": "markdown", - "id": "b38b2739", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "fragment" - }, - "tags": [] - }, - "source": [ - "**AND:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "db33e773", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "a = True\n", - "b = False\n", - "\n", - "a and b" - ] - }, - { - "cell_type": "markdown", - "id": "8b00b658", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "fragment" - }, - "tags": [] - }, - "source": [ - "---\n", - "**OR:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "725d0173", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "a = True\n", - "b = False\n", - "\n", - "a or b" - ] - }, - { - "cell_type": "markdown", - "id": "6a10fe2f", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "---\n", - "**NOT:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27378611", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "a = True\n", - "\n", - "not a" - ] - }, { "cell_type": "markdown", "id": "a5e3ab30", @@ -1489,7 +1331,207 @@ "tags": [] }, "source": [ - "## Repetitions and Conditions" + "## Repetitions and Conditions\n", + "\n", + "First, let's recap boolean logic. Boolean logic uses just two values: True, and False." + ] + }, + { + "cell_type": "markdown", + "id": "9ca15865", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### Boolean" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7b7abb8", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "b1 = False\n", + "b2 = True\n", + "print(b1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9296bb88", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "type(True) # boolean" + ] + }, + { + "cell_type": "markdown", + "id": "eae67d96", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "**Logical Operators** \n", + "We can determine conditions based on Boolean logic: using `and`, `or`, `not` to *evaluate* boolean expressions:" + ] + }, + { + "cell_type": "markdown", + "id": "b38b2739", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "**AND:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db33e773", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "a = True\n", + "b = False\n", + "\n", + "a and b" + ] + }, + { + "cell_type": "markdown", + "id": "5c8055b9-5863-486e-a741-de11eee3faa9", + "metadata": { + "editable": false + }, + "source": [ + "We can display the results of the `AND` operation using a \"truth table\":\n", + "| *and* | True | False |\n", + "| --------- | ----- | ----- |\n", + "| __True__ | True | False |\n", + "| __False__ | False | False |" + ] + }, + { + "cell_type": "markdown", + "id": "8b00b658", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "---\n", + "**OR:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "725d0173", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "a = True\n", + "b = False\n", + "\n", + "a or b" + ] + }, + { + "cell_type": "markdown", + "id": "4a4f35dc-5107-4589-984a-75f7a929958c", + "metadata": { + "editable": false + }, + "source": [ + "| *or* | True | False |\n", + "| --------- | ----- | ----- |\n", + "| __True__ | True | True |\n", + "| __False__ | True | False |\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "6a10fe2f", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "---\n", + "**NOT:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27378611", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "a = True\n", + "\n", + "not a" + ] + }, + { + "cell_type": "markdown", + "id": "bf19d081-ce51-4b07-bc67-94c4569b9ca9", + "metadata": { + "editable": false + }, + "source": [ + "| *not* | True | False |\n", + "| ----- | ----- | ----- |\n", + "| | False | True |" ] }, { @@ -1506,6 +1548,19 @@ "In order to control program flow, and whether or not code is executed, we can do conditions based on variable values." ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fd769b8-28d3-416a-823f-21f7ffcceef7", + "metadata": {}, + "outputs": [], + "source": [ + "if a:\n", + " print(\"a is True!\")\n", + "else:\n", + " print(\"a is False.\")" + ] + }, { "cell_type": "code", "execution_count": null, @@ -5877,7 +5932,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.2" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 03331a1..3c33560 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -678,164 +678,6 @@ "print(\"Exponentiation:\", 2 ** 3)" ] }, - { - "cell_type": "markdown", - "id": "9ca15865", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "#### Boolean" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7b7abb8", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "b1 = False\n", - "b2 = True\n", - "print(b1)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9296bb88", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "type(True) # boolean" - ] - }, - { - "cell_type": "markdown", - "id": "eae67d96", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "**Logical Operators** \n", - "We can also determine conditions based on Boolean logic: `and`, `or`, `not`" - ] - }, - { - "cell_type": "markdown", - "id": "b38b2739", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "fragment" - }, - "tags": [] - }, - "source": [ - "**AND:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "db33e773", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "a = True\n", - "b = False\n", - "\n", - "a and b" - ] - }, - { - "cell_type": "markdown", - "id": "8b00b658", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "fragment" - }, - "tags": [] - }, - "source": [ - "---\n", - "**OR:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "725d0173", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "outputs": [], - "source": [ - "a = True\n", - "b = False\n", - "\n", - "a or b" - ] - }, - { - "cell_type": "markdown", - "id": "6a10fe2f", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "---\n", - "**NOT:**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27378611", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "a = True\n", - "\n", - "not a" - ] - }, { "cell_type": "markdown", "id": "a5e3ab30", @@ -1489,7 +1331,201 @@ "tags": [] }, "source": [ - "## Repetitions and Conditions" + "## Repetitions and Conditions\n", + "\n", + "First, let's recap boolean logic. Boolean logic uses just two values: True, and False." + ] + }, + { + "cell_type": "markdown", + "id": "9ca15865", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "#### Boolean" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7b7abb8", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "b1 = False\n", + "b2 = True\n", + "print(b1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9296bb88", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "type(True) # boolean" + ] + }, + { + "cell_type": "markdown", + "id": "eae67d96", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "**Logical Operators** \n", + "We can determine conditions based on Boolean logic: using `and`, `or`, `not` to *evaluate* boolean expressions:" + ] + }, + { + "cell_type": "markdown", + "id": "b38b2739", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "**AND:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db33e773", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "a = True\n", + "b = False\n", + "\n", + "a and b" + ] + }, + { + "cell_type": "markdown", + "id": "5c8055b9-5863-486e-a741-de11eee3faa9", + "metadata": {}, + "source": [ + "We can display the results of the `AND` operation using a \"truth table\":\n", + "| *and* | True | False |\n", + "| --------- | ----- | ----- |\n", + "| __True__ | True | False |\n", + "| __False__ | False | False |" + ] + }, + { + "cell_type": "markdown", + "id": "8b00b658", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "---\n", + "**OR:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "725d0173", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "outputs": [], + "source": [ + "a = True\n", + "b = False\n", + "\n", + "a or b" + ] + }, + { + "cell_type": "markdown", + "id": "4a4f35dc-5107-4589-984a-75f7a929958c", + "metadata": {}, + "source": [ + "| *or* | True | False |\n", + "| --------- | ----- | ----- |\n", + "| __True__ | True | True |\n", + "| __False__ | True | False |\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "6a10fe2f", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "fragment" + } + }, + "source": [ + "---\n", + "**NOT:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27378611", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "a = True\n", + "\n", + "not a" + ] + }, + { + "cell_type": "markdown", + "id": "bf19d081-ce51-4b07-bc67-94c4569b9ca9", + "metadata": {}, + "source": [ + "| *not* | True | False |\n", + "| ----- | ----- | ----- |\n", + "| | False | True |" ] }, { @@ -1506,6 +1542,19 @@ "In order to control program flow, and whether or not code is executed, we can do conditions based on variable values." ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fd769b8-28d3-416a-823f-21f7ffcceef7", + "metadata": {}, + "outputs": [], + "source": [ + "if a:\n", + " print(\"a is True!\")\n", + "else:\n", + " print(\"a is False.\")" + ] + }, { "cell_type": "code", "execution_count": null, @@ -5904,7 +5953,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "b10a1b92", "metadata": { "editable": true, @@ -5913,15 +5962,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Created example.csv with x and cos(x) values\n" - ] - } - ], + "outputs": [], "source": [ "import csv, math\n", "\n", @@ -5958,7 +5999,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", "metadata": { "editable": true, @@ -5967,20 +6008,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "First few lines of the file:\n", - "x_axis,y_axis\n", - "0.0,1.0\n", - "0.1,0.9950041652780258\n", - "0.2,0.9800665778412416\n", - "0.30000000000000004,0.955336489125606\n" - ] - } - ], + "outputs": [], "source": [ "# Show the first few lines to demonstrate what we created\n", "print(\"First few lines of the file:\")\n", @@ -5991,7 +6019,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "9af8c87f-62db-4a04-86d8-d51428395210", "metadata": { "editable": true, @@ -6000,16 +6028,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The value of Y for X==1.0 saved in the file:\n", - "0.5403023058681398\n" - ] - } - ], + "outputs": [], "source": [ "# Show the value of Y for X==1.0 saved in the file\n", "print(\"The value of Y for X==1.0 saved in the file:\")\n", @@ -6397,7 +6416,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.2" + "version": "3.11.5" } }, "nbformat": 4, From 38c1808bcb09dcec936785f2eee310dfbe6ede05 Mon Sep 17 00:00:00 2001 From: A Naden <46694302+a-naden@users.noreply.github.com> Date: Thu, 26 Feb 2026 11:23:14 +0000 Subject: [PATCH 2/9] Moves the Object oriented programming section. Moves the Object oriented programming section to an optional section at the end, fixes internal anchors for the table of contents. --- Intermediate_full.ipynb | 2310 +++++++++++++++++---------------------- 1 file changed, 987 insertions(+), 1323 deletions(-) diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 3c33560..453486f 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -4,7 +4,6 @@ "cell_type": "markdown", "id": "872c6494", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -20,7 +19,6 @@ "cell_type": "markdown", "id": "2cd478b7", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -47,7 +45,6 @@ "cell_type": "markdown", "id": "4d58fde4", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -72,7 +69,6 @@ "cell_type": "markdown", "id": "e673e2cd", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -86,7 +82,6 @@ "cell_type": "markdown", "id": "85069fdb", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -100,22 +95,21 @@ "- [Part I](#Part-I)\n", " - [1. Recap](#1.-Recap)\n", " - [2. Data structures](#2.-Data-structures)\n", - " - [3. Conditional expression](#3.-Conditional-expressions)\n", + " - [3. Conditional expressions](#3.-Conditional-expressions)\n", " - [4. Comprehensions](#4.-Comprehensions)\n", - " - [5. Exceptions](#5-exceptions)\n", + " - [5. Exceptions](#5.-Exceptions)\n", "\n", "- [Part II](#Part-II)\n", - " - [5. Brief introduction to Object-Oriented Programming](#6-brief-introduction-to-object-oriented-programming)\n", - " - [6. Introduction to modules](#7-introduction-to-modules)\n", - " - [7. Advanced string manipulation](#8-advanced-string-manipulation)\n", - " - [8. (Optional) Working with modules: Examples and creating your own](#9-optional-working-with-modules-examples-and-creating-your-own)\n" + " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", + " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", + " - [8. (Optional) Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", + " - [9. (Optional) Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] }, { "cell_type": "markdown", "id": "153ed362", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -129,7 +123,6 @@ "cell_type": "markdown", "id": "6ba842c0", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -143,7 +136,6 @@ "cell_type": "markdown", "id": "b1d20fc9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -164,7 +156,6 @@ "cell_type": "markdown", "id": "cdfa9441", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -178,7 +169,6 @@ "cell_type": "markdown", "id": "3eadf8e2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -196,7 +186,6 @@ "cell_type": "markdown", "id": "26d2d446", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -210,7 +199,6 @@ "cell_type": "markdown", "id": "4e49802b", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -224,7 +212,6 @@ "cell_type": "markdown", "id": "f99bdeea", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -245,7 +232,6 @@ "cell_type": "markdown", "id": "b721c83a", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -268,7 +254,6 @@ } } }, - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -286,7 +271,6 @@ "execution_count": null, "id": "decd8f2c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -302,7 +286,6 @@ "execution_count": null, "id": "1489fa3d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -318,7 +301,6 @@ "execution_count": null, "id": "fb6110d3", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -333,7 +315,6 @@ "execution_count": null, "id": "ac31e498", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -347,7 +328,6 @@ "cell_type": "markdown", "id": "e1bd297e", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -365,7 +345,6 @@ "execution_count": null, "id": "94b6e716", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -381,7 +360,6 @@ "execution_count": null, "id": "d11dd969", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -396,7 +374,6 @@ "cell_type": "markdown", "id": "2a63c2dd", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -410,7 +387,6 @@ "cell_type": "markdown", "id": "7ab44bf2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -428,7 +404,6 @@ "cell_type": "markdown", "id": "c33c20f5", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -442,7 +417,6 @@ "cell_type": "markdown", "id": "7a797eab", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -462,7 +436,6 @@ "execution_count": null, "id": "c13d9a15", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -478,7 +451,6 @@ "execution_count": null, "id": "26b8760c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -492,7 +464,6 @@ "cell_type": "markdown", "id": "b9324c88", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -506,7 +477,6 @@ "execution_count": null, "id": "3253e3d0", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -523,7 +493,6 @@ "cell_type": "markdown", "id": "397f9f86", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -539,7 +508,6 @@ "execution_count": null, "id": "3342a922", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -555,7 +523,6 @@ "execution_count": null, "id": "36e671e1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -569,7 +536,6 @@ "cell_type": "markdown", "id": "b68a5bbf", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -593,7 +559,6 @@ "execution_count": null, "id": "af62e441", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -608,7 +573,6 @@ "execution_count": null, "id": "7e7ef933", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -623,7 +587,6 @@ "execution_count": null, "id": "28810d42", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -638,7 +601,6 @@ "execution_count": null, "id": "8b66a0a4", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -653,7 +615,6 @@ "execution_count": null, "id": "6984dbe1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -668,7 +629,6 @@ "execution_count": null, "id": "74e37711", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -682,7 +642,6 @@ "cell_type": "markdown", "id": "a5e3ab30", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -696,7 +655,6 @@ "cell_type": "markdown", "id": "ba570bf4", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -710,7 +668,6 @@ "execution_count": null, "id": "ea3df5a1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -728,7 +685,6 @@ "execution_count": null, "id": "e3c09d2d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -743,7 +699,6 @@ "cell_type": "markdown", "id": "50a4347d", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -760,7 +715,6 @@ "execution_count": null, "id": "d9fadfdc", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -776,7 +730,6 @@ "cell_type": "markdown", "id": "d20cb9b3", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -790,7 +743,6 @@ "cell_type": "markdown", "id": "7ac031a7", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -805,7 +757,6 @@ "execution_count": null, "id": "41b7cdfe", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -823,7 +774,6 @@ "execution_count": null, "id": "9c50f102", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -842,7 +792,6 @@ "execution_count": null, "id": "3f72dedf", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -860,7 +809,6 @@ "cell_type": "markdown", "id": "8ee98ee9", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -874,7 +822,6 @@ "cell_type": "markdown", "id": "6b2e3c6e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -889,7 +836,6 @@ "execution_count": null, "id": "a1178a62", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -906,7 +852,6 @@ "cell_type": "markdown", "id": "52819c95", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -920,7 +865,6 @@ "cell_type": "markdown", "id": "a0966820", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -945,7 +889,6 @@ "execution_count": null, "id": "38966db9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -963,7 +906,6 @@ "cell_type": "markdown", "id": "aadba414", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -983,7 +925,6 @@ "execution_count": null, "id": "7f0a6056", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1000,7 +941,6 @@ "execution_count": null, "id": "ec567746", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1016,7 +956,6 @@ "cell_type": "markdown", "id": "1f1185e6", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1030,7 +969,6 @@ "cell_type": "markdown", "id": "179f132a", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1044,7 +982,6 @@ "cell_type": "markdown", "id": "e998f8fe", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1059,7 +996,6 @@ "execution_count": null, "id": "911d44b3", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1076,7 +1012,6 @@ "cell_type": "markdown", "id": "b61a8691", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1090,7 +1025,6 @@ "cell_type": "markdown", "id": "9c82edee", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1108,7 +1042,6 @@ "cell_type": "markdown", "id": "8bb91a15", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1125,7 +1058,6 @@ "execution_count": null, "id": "fdc8600e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1141,7 +1073,6 @@ "cell_type": "markdown", "id": "efc747a1", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1157,7 +1088,6 @@ "execution_count": null, "id": "2b2c4dee", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1172,7 +1102,6 @@ "execution_count": null, "id": "3f87d56b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1187,7 +1116,6 @@ "execution_count": null, "id": "b686d58d", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1203,7 +1131,6 @@ "execution_count": null, "id": "1f916c68", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1217,7 +1144,6 @@ "cell_type": "markdown", "id": "b8369a1a", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1233,7 +1159,6 @@ "execution_count": null, "id": "e0fac9bf", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1249,7 +1174,6 @@ "execution_count": null, "id": "586edf14", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1264,7 +1188,6 @@ "execution_count": null, "id": "9f0dea38", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1279,7 +1202,6 @@ "execution_count": null, "id": "bab8e8a0", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1293,7 +1215,6 @@ "cell_type": "markdown", "id": "fe6ffaf2", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1309,7 +1230,6 @@ "execution_count": null, "id": "0edf3fa6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1324,7 +1244,6 @@ "cell_type": "markdown", "id": "f87cfa0f", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1340,7 +1259,6 @@ "cell_type": "markdown", "id": "9ca15865", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -1354,7 +1272,6 @@ "execution_count": null, "id": "d7b7abb8", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1371,7 +1288,6 @@ "execution_count": null, "id": "9296bb88", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1385,7 +1301,6 @@ "cell_type": "markdown", "id": "eae67d96", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1400,7 +1315,6 @@ "cell_type": "markdown", "id": "b38b2739", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1415,7 +1329,6 @@ "execution_count": null, "id": "db33e773", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1445,7 +1358,6 @@ "cell_type": "markdown", "id": "8b00b658", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1461,7 +1373,6 @@ "execution_count": null, "id": "725d0173", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1490,7 +1401,6 @@ "cell_type": "markdown", "id": "6a10fe2f", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -1505,7 +1415,6 @@ "execution_count": null, "id": "27378611", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1532,7 +1441,6 @@ "cell_type": "markdown", "id": "9303b3ff", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -1560,7 +1468,6 @@ "execution_count": null, "id": "a0af6ea1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1589,7 +1496,6 @@ "cell_type": "markdown", "id": "3246bbe1", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1606,7 +1512,6 @@ "execution_count": null, "id": "8cab77e6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1628,7 +1533,6 @@ "cell_type": "markdown", "id": "8c87d3f8", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1643,7 +1547,6 @@ "cell_type": "markdown", "id": "095edef4", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1659,7 +1562,6 @@ "execution_count": null, "id": "c7dc2e03", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1677,7 +1579,6 @@ "cell_type": "markdown", "id": "76e99a09", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -1690,7 +1591,6 @@ "cell_type": "markdown", "id": "e5b05a2c", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1706,7 +1606,6 @@ "execution_count": null, "id": "b14f546d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1723,7 +1622,6 @@ "execution_count": null, "id": "713884f6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1739,7 +1637,6 @@ "execution_count": null, "id": "b3078796", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1754,7 +1651,6 @@ "cell_type": "markdown", "id": "99b52e73", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1772,7 +1668,6 @@ "execution_count": null, "id": "136268d9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1790,7 +1685,6 @@ "cell_type": "markdown", "id": "89cd06cc", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -1804,7 +1698,6 @@ "cell_type": "markdown", "id": "b6c7b631", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -1817,7 +1710,6 @@ "cell_type": "markdown", "id": "ad3766a1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1835,7 +1727,6 @@ "cell_type": "markdown", "id": "b83eb9fd", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1850,7 +1741,6 @@ "cell_type": "markdown", "id": "25dddacf", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1865,7 +1755,6 @@ "cell_type": "markdown", "id": "aa2983d4", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1880,7 +1769,6 @@ "execution_count": null, "id": "d4ca99fa", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1900,7 +1788,6 @@ "cell_type": "markdown", "id": "429c78c2", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1914,7 +1801,6 @@ "cell_type": "markdown", "id": "f64d31aa", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1930,7 +1816,6 @@ "execution_count": null, "id": "643f4038", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1953,7 +1838,6 @@ "cell_type": "markdown", "id": "b07b62ef", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -1966,7 +1850,6 @@ "cell_type": "markdown", "id": "7e95592e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1983,7 +1866,6 @@ "cell_type": "markdown", "id": "aae1eed3", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -1999,7 +1881,6 @@ "execution_count": null, "id": "cb25df04", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2017,7 +1898,6 @@ "cell_type": "markdown", "id": "50327676", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2031,7 +1911,6 @@ "execution_count": null, "id": "250138ea", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2047,7 +1926,6 @@ "cell_type": "markdown", "id": "5bda75d6", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2063,7 +1941,6 @@ "execution_count": null, "id": "e1027891", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2081,7 +1958,6 @@ "execution_count": null, "id": "48a12e4a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2098,7 +1974,6 @@ "cell_type": "markdown", "id": "7e4b1b25", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2112,7 +1987,6 @@ "execution_count": null, "id": "3a23bbd1", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2129,7 +2003,6 @@ "cell_type": "markdown", "id": "290722a8", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2145,7 +2018,6 @@ "execution_count": null, "id": "54db3f5f", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2162,7 +2034,6 @@ "cell_type": "markdown", "id": "81d1f392", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2176,7 +2047,6 @@ "execution_count": null, "id": "230fdc57", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2194,7 +2064,6 @@ "cell_type": "markdown", "id": "f6fce9a1", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2208,7 +2077,6 @@ "execution_count": null, "id": "100c9390", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2226,7 +2094,6 @@ "cell_type": "markdown", "id": "b26074d7", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2240,7 +2107,6 @@ "execution_count": null, "id": "5279a6b8", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2257,7 +2123,6 @@ "execution_count": null, "id": "ad34c0bf", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2274,7 +2139,6 @@ "cell_type": "markdown", "id": "e00e5f84", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2291,7 +2155,6 @@ "execution_count": null, "id": "0e61b0ef", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2310,7 +2173,6 @@ "cell_type": "markdown", "id": "8be77c84", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2325,7 +2187,6 @@ "execution_count": null, "id": "867aa292", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2341,7 +2202,6 @@ "cell_type": "markdown", "id": "04d87890", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2357,7 +2217,6 @@ "execution_count": null, "id": "3afd38d5", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2375,7 +2234,6 @@ "execution_count": null, "id": "4bf75e76", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2397,7 +2255,6 @@ "execution_count": null, "id": "4775ecb7", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "fragment" @@ -2423,7 +2280,6 @@ "execution_count": null, "id": "8f3c40be", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2441,7 +2297,6 @@ "cell_type": "markdown", "id": "812d5a14", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -2455,7 +2310,6 @@ "cell_type": "markdown", "id": "66b0bb86", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2471,7 +2325,6 @@ "execution_count": null, "id": "a9622e5a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2490,7 +2343,6 @@ "execution_count": null, "id": "95e68a89", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2509,7 +2361,6 @@ "execution_count": null, "id": "d84ee17a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2526,7 +2377,6 @@ "cell_type": "markdown", "id": "4131293a", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -2555,7 +2405,6 @@ "cell_type": "markdown", "id": "03763f24", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2571,7 +2420,6 @@ "execution_count": null, "id": "18bac89c", "metadata": { - "editable": true, "remove_code": "after:# Generate new list with unique values", "slideshow": { "slide_type": "" @@ -2591,7 +2439,6 @@ "cell_type": "markdown", "id": "d0501b3f", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -2607,7 +2454,6 @@ "execution_count": null, "id": "a924df94", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -2627,7 +2473,6 @@ "cell_type": "markdown", "id": "245d1725", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2642,7 +2487,6 @@ "cell_type": "markdown", "id": "8b83afd4", "metadata": { - "editable": true, "slideshow": { "slide_type": null }, @@ -2664,7 +2508,6 @@ "execution_count": null, "id": "200a2eba", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -2681,7 +2524,6 @@ "execution_count": null, "id": "553707eb", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2702,7 +2544,6 @@ "execution_count": null, "id": "eb9476c1", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2721,7 +2562,6 @@ "execution_count": null, "id": "112e1c7b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2740,7 +2580,6 @@ "execution_count": null, "id": "9affafb3", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2758,7 +2597,6 @@ "cell_type": "markdown", "id": "de3b6a25-6150-4fb7-8cab-e97872f8974e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2781,7 +2619,6 @@ "execution_count": null, "id": "a71f9c99-e59e-4470-aa19-fde963cbb276", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2807,7 +2644,6 @@ "execution_count": null, "id": "3a6e30f1-c169-4ecb-9d59-f0e7cef1fb56", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2825,7 +2661,6 @@ "cell_type": "markdown", "id": "968a105e-1cc1-45e7-aa30-d19ce18943fe", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2848,7 +2683,6 @@ "execution_count": null, "id": "6081d62b-efd5-4b51-ba91-7307e53c9a36", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2867,7 +2701,6 @@ "execution_count": null, "id": "b65b03ae-768e-4bee-8502-b0ea4d633e5c", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2886,7 +2719,6 @@ "execution_count": null, "id": "2ff80eea-453f-44ac-8ddf-5f084008127b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2904,7 +2736,6 @@ "cell_type": "markdown", "id": "f73a79d3", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2918,7 +2749,6 @@ "cell_type": "markdown", "id": "624091b9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -2934,7 +2764,6 @@ "cell_type": "markdown", "id": "7271e95a", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -2952,7 +2781,6 @@ "execution_count": null, "id": "502cadb7", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2972,7 +2800,6 @@ "execution_count": null, "id": "3f76fba0", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2991,7 +2818,6 @@ "cell_type": "markdown", "id": "b35c5868", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -3008,7 +2834,6 @@ "execution_count": null, "id": "662c5a6c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3031,7 +2856,6 @@ "cell_type": "markdown", "id": "70429b28", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3046,7 +2870,6 @@ "execution_count": null, "id": "ceb379c2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3065,7 +2888,6 @@ "execution_count": null, "id": "d7738594", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3083,7 +2905,6 @@ "cell_type": "markdown", "id": "36c080f0", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -3101,7 +2922,6 @@ "execution_count": null, "id": "e4dfb2cb", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3119,7 +2939,6 @@ "cell_type": "markdown", "id": "b424a761", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3133,7 +2952,6 @@ "cell_type": "markdown", "id": "38cc0279", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -3146,7 +2964,6 @@ "cell_type": "markdown", "id": "3f494a2e", "metadata": { - "editable": true, "lines_to_next_cell": 2, "slideshow": { "slide_type": "" @@ -3162,7 +2979,6 @@ "execution_count": null, "id": "3ae9acd3", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3202,7 +3018,6 @@ "cell_type": "markdown", "id": "1178f7dc", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3216,7 +3031,6 @@ "cell_type": "markdown", "id": "31e0b17b", "metadata": { - "editable": true, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "" @@ -3234,7 +3048,6 @@ "execution_count": null, "id": "d3e579d3", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3264,7 +3077,6 @@ "cell_type": "markdown", "id": "07d53abe", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3278,7 +3090,6 @@ "cell_type": "markdown", "id": "6e83da5f", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -3292,7 +3103,6 @@ "execution_count": null, "id": "fb62cca7", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3316,7 +3126,6 @@ "cell_type": "markdown", "id": "8eb3bbf7", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" } @@ -3330,7 +3139,6 @@ "cell_type": "markdown", "id": "f2ad81c8", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3344,7 +3152,6 @@ "cell_type": "markdown", "id": "7c84ec76", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -3358,7 +3165,6 @@ "execution_count": null, "id": "f964f97b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3373,7 +3179,6 @@ "cell_type": "markdown", "id": "01378c1c", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -3387,7 +3192,6 @@ "execution_count": null, "id": "9ad284dd", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3416,7 +3220,6 @@ "cell_type": "markdown", "id": "5bc9a961", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3432,7 +3235,6 @@ "execution_count": null, "id": "56986833", "metadata": { - "editable": true, "remove_code": "after:# shorten by ternary expression", "slideshow": { "slide_type": "fragment" @@ -3458,7 +3260,6 @@ "cell_type": "markdown", "id": "21217bab", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -3474,7 +3275,6 @@ "execution_count": null, "id": "81768bf7", "metadata": { - "editable": true, "remove_code": "# catch None with or", "slideshow": { "slide_type": "" @@ -3494,7 +3294,6 @@ "cell_type": "markdown", "id": "63274497", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -3510,7 +3309,6 @@ "execution_count": null, "id": "40fb97c5", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3530,7 +3328,6 @@ "execution_count": null, "id": "23e5335e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3545,7 +3342,6 @@ "cell_type": "markdown", "id": "a6f9d70c-8116-4e65-b719-e3eb2afa7338", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3559,7 +3355,6 @@ "cell_type": "markdown", "id": "6dd1230b", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -3574,7 +3369,6 @@ "execution_count": null, "id": "30eb5d01", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3596,7 +3390,6 @@ "cell_type": "markdown", "id": "f77b3d5e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3610,7 +3403,6 @@ "cell_type": "markdown", "id": "0002904e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" } @@ -3625,7 +3417,6 @@ "execution_count": null, "id": "d2d4f618", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -3642,7 +3433,6 @@ "cell_type": "markdown", "id": "2b2a108f", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -3656,7 +3446,6 @@ "execution_count": null, "id": "8e6b943b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3674,7 +3463,6 @@ "cell_type": "markdown", "id": "fba1d4bd", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -3688,7 +3476,6 @@ "execution_count": null, "id": "7fa7800c", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3715,7 +3502,6 @@ "execution_count": null, "id": "ef3ac491-86bf-4e69-9c32-1e320773202d", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3732,7 +3518,6 @@ "cell_type": "markdown", "id": "23631ac8", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3747,7 +3532,6 @@ "execution_count": null, "id": "b19190dc", "metadata": { - "editable": true, "remove_code": "after:# print a dictionaries of lengths for the names", "slideshow": { "slide_type": "" @@ -3767,7 +3551,6 @@ "cell_type": "markdown", "id": "2d4e0235", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3782,7 +3565,6 @@ "execution_count": null, "id": "27175fde", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3800,7 +3582,6 @@ "cell_type": "markdown", "id": "f8beaad4", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3820,7 +3601,6 @@ "execution_count": null, "id": "72ee6d83", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3840,7 +3620,6 @@ "cell_type": "markdown", "id": "2092afdb", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3856,7 +3635,6 @@ "execution_count": null, "id": "9dc013da", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "after:# your solution", "slideshow": { @@ -3877,7 +3655,6 @@ "cell_type": "markdown", "id": "6e54d68e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3903,7 +3680,6 @@ "cell_type": "markdown", "id": "b70b9fb0", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" }, @@ -3924,7 +3700,6 @@ "cell_type": "markdown", "id": "e4ffd520", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3961,7 +3736,6 @@ "cell_type": "markdown", "id": "8986cf90", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" }, @@ -3978,7 +3752,6 @@ "cell_type": "markdown", "id": "d26956f3", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -3993,7 +3766,6 @@ "execution_count": null, "id": "6a7114a0", "metadata": { - "editable": true, "remove_code": "after:# Modify function to list the index and content of the entry that caused the error", "slideshow": { "slide_type": "" @@ -4033,7 +3805,6 @@ "cell_type": "markdown", "id": "7b376a1f", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" }, @@ -4050,7 +3821,6 @@ "cell_type": "markdown", "id": "44d08a7e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -4092,7 +3862,6 @@ "cell_type": "markdown", "id": "8903db8d", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" }, @@ -4108,7 +3877,6 @@ "cell_type": "markdown", "id": "6011ded7", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -4134,7 +3902,6 @@ "execution_count": null, "id": "6401f075", "metadata": { - "editable": true, "remove_code": "after:# Modify function to always include the timing", "slideshow": { "slide_type": "" @@ -4182,7 +3949,6 @@ "cell_type": "markdown", "id": "e792e5a8", "metadata": { - "editable": true, "slideshow": { "slide_type": "notes" }, @@ -4198,7 +3964,6 @@ "cell_type": "markdown", "id": "bbc81d0f", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -4221,7 +3986,6 @@ "cell_type": "markdown", "id": "67e040dc", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -4235,7 +3999,6 @@ "cell_type": "markdown", "id": "ff630616", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4289,7 +4052,6 @@ "cell_type": "markdown", "id": "930a9ea5", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -4301,60 +4063,79 @@ }, { "cell_type": "markdown", - "id": "9e01e73d", + "id": "ecad0562", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "# 6. Brief introduction to Object-Oriented Programming" + "# 6. Introduction to modules\n", + "A _module_ is a single file (or collection of files) that is intended to be imported and used in other Python programs. It can include functions, classes, variables, and runnable code." ] }, { "cell_type": "markdown", - "id": "3627c2ef", + "id": "9e1c43a8", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, "source": [ - "* Python is an object oriented programming language. Object-Oriented Programming (OOP) is a programming paradigm based on the concept of \"objects\" which can contain:\n", - " - Data (attributes)\n", - " - Code (methods)" + "## Importing _modules_" ] }, { "cell_type": "markdown", - "id": "8393fae9", + "id": "eed64626", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" + } + }, + "source": [ + "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." + ] + }, + { + "cell_type": "markdown", + "id": "db90a278", + "metadata": { + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "There are several ways of importing _modules_:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f8ee4bb", + "metadata": { + "slideshow": { + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ + "# import the whole module\n", + "import math\n", "\n", - "## 1. Classes and Objects\n", - " - Class: A blueprint for creating objects (Think a cookiecutter)\n", - " - Object: An instance of a class (The created cookies)\n", - "\n", - "\n", - "A simple example:" + "# module's function name is in the module's namespace\n", + "print(math.sqrt(16.0))" ] }, { "cell_type": "code", "execution_count": null, - "id": "5005c5bc", + "id": "338eca3f", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4362,61 +4143,51 @@ }, "outputs": [], "source": [ - "# Simple example\n", - "class CourseParticipant:\n", - " def __init__(self, name, email):\n", - " self.name = name\n", - " self.email = email\n", - "\n", - " def welcome(self):\n", - " print(f\"Welcome {self.name}! We're glad to have you.\")\n", - "\n", - "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", - "participant1.welcome()" + "# import several modules at once\n", + "import pathlib, sys, time" ] }, { - "cell_type": "markdown", - "id": "d9003b8b", + "cell_type": "code", + "execution_count": null, + "id": "2f29773e", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "Speaker notes:\n", - "\n", - "The parts are:\n", - "- `class ClassName`: Classes are created with the `class` keyword and named in CamelCase\n", - "- `def __init__...`: The constructor method. This is used to create a new instance (cookie), with a given set of input variables. The first one is the reference to a given object created from the class (`self`), which is used to store the data/state.\n", - "- `def method_name(self)`: A method name. We again use `self` as the reference to an object created from the class" + "# use 'as' keyword to change the name of the module\n", + "import math as m\n", + "print(m.sqrt(36.0))" ] }, { - "cell_type": "markdown", - "id": "b2a91e2a", + "cell_type": "code", + "execution_count": null, + "id": "77b96e95", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## 2. Encapsulation\n", - " - Bundling data and methods that work on that data within one unit\n", - " - Restricting access to certain details\n", - " - Is also often used to keep track of states." + "# import only a selected function from a module\n", + "from math import sqrt\n", + "\n", + "# the function's name is in the global namespace\n", + "print(sqrt(49))" ] }, { "cell_type": "code", "execution_count": null, - "id": "74cd0847", + "id": "ce4f29f0", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4424,200 +4195,135 @@ }, "outputs": [], "source": [ - "class CourseParticipant:\n", - " def __init__(self, name, email):\n", - " self.name = name\n", - " self.email = email\n", - " self.registered_attendance = False\n", - "\n", - " def welcome(self):\n", - " print(f\"Welcome {self.name}! We're glad to have you.\")\n", - "\n", - " def register_attendance(self):\n", - " self.registered_attendance = True\n", - " print(f\"{self.name} has been registered for attendance.\")\n", - "\n", - "# use the class\n", - "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", - "participant1.welcome()\n", - "participant1.register_attendance()\n" + "# change the name of the function in the module\n", + "from math import sqrt as square_root\n", + "print(square_root(25))" ] }, { - "cell_type": "markdown", - "id": "915e7f40", + "cell_type": "code", + "execution_count": null, + "id": "44c18b00", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "Speaker notes:\n", - " - Imagine we need a function to track whether users have attended the course.\n", - " - We can change the internal state of the object representing a given participant.\n", - " - By checking the registered_attendance attribute, we can track which participants have registered" + "# import all functions, variables, and classes from a module into the global namespace\n", + "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", + "from math import *\n", + "print(int(sqrt(4.0)))" ] }, { "cell_type": "markdown", - "id": "df442469", + "id": "d1cc0855", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, "source": [ - "## 3. Inheritance\n", - " - Creating new classes that extend the functionality of existing classes\n", - " - We _inherit_ the properties of the base class `CourseParticipant`\n", - " - `super()` lets us invoke the function of the same name from the base class\n", - " - Carefully decide between inheritance and composition (see soon)" + "---\n", + "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." ] }, { "cell_type": "code", "execution_count": null, - "id": "8e94ff6d", + "id": "558e0d9e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" - }, - "tags": [] + } }, "outputs": [], "source": [ - "class ExternalParticipant(CourseParticipant):\n", - " def __init__(self, name, email, company):\n", - " super().__init__(name, email)\n", - " self.company = company\n", - "\n", - " def contact_company(self):\n", - " print(f\"Contacting {self.company} regarding course participation.\")\n", - "\n", - "external_participant1 = ExternalParticipant(\"Bob\", \"bob@example.com\", \"Cooperative Inc.\")\n", - "external_participant1.welcome()\n", - "external_participant1.contact_company()\n" + "# get a list of the functions and variables in the module\n", + "dir(math)" ] }, { - "cell_type": "markdown", - "id": "206d9ee0", + "cell_type": "code", + "execution_count": null, + "id": "01d2c703", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" - }, - "tags": [] + "slide_type": "" + } }, + "outputs": [], "source": [ - "Speaker notes:\n", - "\n", - "Now imagine we can have external participants that are affiliated with a company. We want our object to have all the functionality of our `CourseParticipant` class, but also have additional functionality that is specific to our external participants." + "# get a long description\n", + "help(math)" ] }, { "cell_type": "markdown", - "id": "2cf3958b", + "id": "8e33b8e3", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" - }, - "tags": [] + "slide_type": "fragment" + } }, "source": [ - "## 4. Polymorphism\n", - "- Definition: Call the same method name on different object types and get type-specific behavior.\n", - "- Key idea: Write code to an interface, not a concrete class.\n", - "- Why it matters:\n", - " - Decouples caller from concrete types (extensible)\n", - " - Removes conditionals/type-checks (cleaner)\n", - " - Eases testing and substitution (mocks/fakes)" + "---" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "a414bc89", + "cell_type": "markdown", + "id": "2d186e61-b776-483a-a6b9-0890af512e80", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "class DurhamUniversityParticipant(CourseParticipant):\n", - " def register_attendance(self):\n", - " super().register_attendance()\n", - " print(f\" Also registered attendance with the internal additional system for {self.name}\")\n", - " \n", - "\n", - "participants = [\n", - " ExternalParticipant(\"Alice\", \"alice@example.com\", \"Acme Corp\"),\n", - " DurhamUniversityParticipant(\"Bob\", \"bob@durham.ac.uk\"),\n", - " CourseParticipant(\"Charlie\", \"charlie@example.com\")\n", - "]\n", - "\n", - "for participant in participants:\n", - " participant.register_attendance()" + "# 7. Advanced string manipulation" ] }, { "cell_type": "markdown", - "id": "5385bec2", + "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "" }, "tags": [] }, "source": [ - "Speaker notes:\n", - "\n", - "Say for registering the attendance for our internal participants we are also required to call an API function (represented by the print statement here). We can overwrite the function to behave differently for the `DurhamUniveristyParticipant` class\n", - "\n", - " - We are using `super()` again. Note that this is not necessary\n", - " - We can still just use `register_attendance()` even though one of the functions now behaves differently.\n", - " - If there are lots of `if/else` statements depending on which type an programmed structure represents, objects with different types can simplify the structure significantly.\n", - " - It is quite easy to introduce an additional class that has another option for the behaviour." + "* Adjusting case\n", + "* Formatting strings\n", + " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", + "* Quering the existence, replacing, splitting" ] }, { "cell_type": "markdown", - "id": "fdb800a8", + "id": "00e14678-81a2-4509-815a-53f9f2fdb332", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "## 5. Composition\n", - "\n", - "- Definition: Build classes by combining other objects (a class has collaborators).\n", - "- Why choose it:\n", - " - Favors flexibility and reuse over tight inheritance ties\n", - " - Swap components easily\n", - "\n", - "- If your `__init__` functions have alternative optional parameters, this is often a sign you should use composition\n", - "- Especially favour composition if there are several options for different behaviours that can be combined interchangeably (_has-a_ vs interitance: _is-a_)\n" + "## Finding values \n", + "* `find()` and `index()` both return index of a substring,\n", + " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", + " - `find()` returns `-1` when a values was not found\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "2cea837b", + "id": "0eab0a2d-eea9-4c33-b700-56eb293ef28b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4625,194 +4331,94 @@ }, "outputs": [], "source": [ - "class Messenger:\n", - " def send_message(self, message):\n", - " pass\n", - "\n", - "class EmailMessenger(Messenger):\n", - "\n", - " def __init__(self, email):\n", - " self.email = email\n", - "\n", - " def send_message(self, message):\n", - " print(f\"Sending email to {self.email}: {message}\")\n", - "\n", - "class TeamsMessenger(Messenger):\n", - "\n", - " def __init__(self, user_id):\n", - " self.user_id = user_id\n", - "\n", - " def send_message(self, message):\n", - " print(f\"Sending Teams message to {self.user_id}: {message}\")\n", - "\n", - "\n", - "class Participant:\n", - " def __init__(self, name, messenger):\n", - " self.name = name\n", - " self.messenger = messenger\n", - "\n", - " def welcome(self):\n", - " self.messenger.send_message(f\"Welcome {self.name}!\")\n", - "\n", - "# Use the Participant class\n", - "participants = [\n", - " Participant(\"Alice\", EmailMessenger(\"alice@example.com\")),\n", - " Participant(\"Bob\", TeamsMessenger(\"bob123\"))\n", - "]\n", - "\n", - "for participant in participants:\n", - " participant.welcome()\n" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "print(line.find('fox'))\n", + "print(line.index('fox'))" ] }, { - "cell_type": "markdown", - "id": "7ea0b8f0", + "cell_type": "code", + "execution_count": null, + "id": "134c6eba-8897-4ee8-a6e5-f3740a0a4d21", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "Speaker notes\n", - " - In this example, participants can be contacted via e-mail or Teams\n", - " - The information we need for the two contact possibilities is completely independent\n", - " - The specific behaviour is used by the class, but the details are not important for the class\n", - " - So each object `has-a` messenger that can be used to contact the participant\n", - " - It is straightforward to inherit the different participant classes (External / DU) using this messenger, without creating four (Messing (2) x DU/External (2)) classes that would be needed with inheritance also\n" - ] - }, - { - "cell_type": "markdown", - "id": "129df112", - "metadata": {}, - "source": [ - "---" + "print(line.find('wombat'))" ] }, { - "cell_type": "markdown", - "id": "d9c8cd20", + "cell_type": "code", + "execution_count": null, + "id": "fc5a28ef-8a31-434a-a653-1662cc274945", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Have a play!" + "try:\n", + " print(line.index('wombat'))\n", + "except ValueError:\n", + " print(\"A wombat isn't mentioned in the text\")" ] }, { "cell_type": "markdown", - "id": "4858e58f", + "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", "metadata": { - "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "slide" }, "tags": [] }, "source": [ - "Speaker notes:\n", - "\n", - "While the explanations went quite a bit further, this example only needs the application of encapsulation. Packaging up basic Application Programming Interfaces (APIs) into a more useable form is a useful and common application of OOP. In the interest of time / scope we will keep the exercise a bit more simple, but feel free to also inquire about the other concepts while you work on it." + "## Checking conditions on strings" ] }, { "cell_type": "markdown", - "id": "28e31e47", + "id": "7b5ac28b-5cfb-4c43-bf54-093c240cbe2b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ - "### Plant Sensor API Exercise\n", - "You've been given a virtual sensor API module which you can import with (`import sensor_api`) that can monitor plants. \n", - "The API provides three functions:\n", - "\n", - "- `connect(sensor_id)`: Connects to a sensor (returns True/False)\n", - "- `disconnect(sensor_id)`: Disconnects from a sensor (returns True/False) \n", - "- `send_message(message)`: Sends a command and receives a reading (returns float or None)\n", - "\n", - "#### Message Format\n", - "Messages must be formatted as: `\"SENSOR_ID:COMMAND\"`\n", - "\n", - "Available commands:\n", - "- `SOIL_HUMIDITY`: Get soil humidity (0-100%)\n", - "- `AIR_HUMIDITY`: Get air humidity (0-100%)\n", - "- `TEMPERATURE`: Get temperature in Celsius\n", - "\n", - "#### Before\n", - "This is how working with the API would currently look:\n", - "\n", - "```python\n", - "import sensor_api\n", - "\n", - "sensor_id = \"GREENHOUSE_01\"\n", - "sensor_api.connect(sensor_id)\n", - "\n", - "soil_humidity = float(sensor_api.send_message(f\"{id}:SOIL_HUMIDITY\"))\n", - "air_humidity = float(sensor_api.send_message(f\"{id}:AIR_HUMIDITY\"))\n", - "temperature = float(sensor_api.send_message(f\"{id}:TEMPERATURE\"))\n", - "\n", - "print(f\"\\n=== Plant Sensor {sensor_id} Readings ===\")\n", - "print(f\"Soil Humidity: {soil_humidity}%\")\n", - "print(f\"Air Humidity: {air_humidity}%\")\n", - "print(f\"Temperature: {temperature}ยฐC\")\n", - "print(\"=\" * 35)\n", - "sensor_api.disconnect(id)\n", - "```\n", - "\n", - "#### Your Task\n", - "Create a `PlantSensor` class that:\n", - "\n", - "1. Stores the sensor ID when created\n", - "2. Automatically connects when initialized\n", - "3. Provides easy-to-use methods for each measurement type\n", - "4. Properly disconnects when done\n", - "5. Displays all readings in a nice format\n", - "\n", - "\n", - "\n", - "#### Desired result\n", - "```python\n", - "# This is how your class should work:\n", - "sensor = PlantSensor(\"PLANT_01\")\n", - "soil = sensor.get_soil_humidity()\n", - "air = sensor.get_air_humidity()\n", - "temp = sensor.get_temperature()\n", - "sensor.display_readings()\n", - "sensor.disconnect()\n", - "```" + "* Checking whether a string starts or ends a certain way is really common and easy" ] }, { - "cell_type": "markdown", - "id": "9cb57fee", + "cell_type": "code", + "execution_count": null, + "id": "77d4d329-9e07-4100-a84e-bd8e55287b5d", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "### Implementation" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "\n", + "print(line.startswith('the')) # True\n", + "print(line.endswith('dog')) # True - makes sense!\n", + "print(line.endswith('fox')) # False - now it's clear why" ] }, { "cell_type": "code", "execution_count": null, - "id": "fb0d76f6", + "id": "7e401e7c-4cc2-4de7-8e11-45654b9592b9", "metadata": { - "editable": true, - "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -4820,72 +4426,29 @@ }, "outputs": [], "source": [ - "import sensor_api\n", - "\n", - "class PlantSensor:\n", - " def __init__(self, sensor_id):\n", - " \"\"\"Initialize the sensor with an ID and connect to it.\"\"\"\n", - " self.sensor_id = sensor_id\n", - " self.connected = sensor_api.connect(sensor_id)\n", - " \n", - " # Store readings\n", - " self.soil_humidity = None\n", - " self.air_humidity = None\n", - " self.temperature = None\n", - " \n", - " def get_soil_humidity(self):\n", - " \"\"\"Get soil humidity reading.\"\"\"\n", - " if self.connected:\n", - " message = f\"{self.sensor_id}:SOIL_HUMIDITY\"\n", - " self.soil_humidity = float(sensor_api.send_message(message))\n", - " return self.soil_humidity\n", - " return None\n", - " \n", - " def get_air_humidity(self):\n", - " \"\"\"Get air humidity reading.\"\"\"\n", - " if self.connected:\n", - " message = f\"{self.sensor_id}:AIR_HUMIDITY\"\n", - " self.air_humidity = float(sensor_api.send_message(message))\n", - " return self.air_humidity\n", - " return None\n", - " \n", - " def get_temperature(self):\n", - " \"\"\"Get temperature reading.\"\"\"\n", - " if self.connected:\n", - " message = f\"{self.sensor_id}:TEMPERATURE\"\n", - " self.temperature = float(sensor_api.send_message(message))\n", - " return self.temperature\n", - " return None\n", - " \n", - " def display_readings(self):\n", - " \"\"\"Display all sensor readings.\"\"\"\n", - " print(f\"\\n=== Plant Sensor {self.sensor_id} Readings ===\")\n", - " print(f\"Soil Humidity: {self.soil_humidity}%\")\n", - " print(f\"Air Humidity: {self.air_humidity}%\")\n", - " print(f\"Temperature: {self.temperature}ยฐC\")\n", - " print(\"=\" * 35)\n", - " \n", - " def disconnect(self):\n", - " \"\"\"Disconnect from the sensor.\"\"\"\n", - " if self.connected:\n", - " sensor_api.disconnect(self.sensor_id)\n", - " self.connected = False" + "# Case sensitivity matters\n", + "print(line.startswith('The')) # False - capital T\n", + "print(line.startswith('the')) # True - lowercase t" ] }, { "cell_type": "markdown", - "id": "1624a7a4", - "metadata": {}, + "id": "e040bf97-a6bd-493e-b047-2041b5a99131", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, "source": [ - "You can use this to try to use your class. You can comment out functionality, if you have not implemented it yet" + "* The canonical way to search a string (if not interested in the index):" ] }, { "cell_type": "code", "execution_count": null, - "id": "49d66487", + "id": "47c2d357", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4893,101 +4456,58 @@ }, "outputs": [], "source": [ - "my_plant = PlantSensor(\"GREENHOUSE_01\")\n", - "\n", - "# Take readings\n", - "my_plant.get_soil_humidity()\n", - "my_plant.get_air_humidity()\n", - "my_plant.get_temperature()\n", - "\n", - "# Display results\n", - "my_plant.display_readings()\n", - "\n", - "# Clean up\n", - "my_plant.disconnect()" + "if \"fox\" in line:\n", + " print(\"A fox has been seen\")" ] }, { "cell_type": "markdown", - "id": "ecad0562", + "id": "fe3ce02d-08bd-4c52-a935-d27b843dde39", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "# 7. Introduction to modules\n", - "A _module_ is a single file (or collection of files) that is intended to be imported and used in other Python programs. It can include functions, classes, variables, and runnable code." + "## Replacing a value:" ] }, { - "cell_type": "markdown", - "id": "9e1c43a8", + "cell_type": "code", + "execution_count": null, + "id": "292d8b56-1142-4927-9320-9c6331f5a962", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Importing _modules_" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "print(line)\n", + "print(line.replace('brown', 'red'))" ] }, { "cell_type": "markdown", - "id": "eed64626", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "source": [ - "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." - ] - }, - { - "cell_type": "markdown", - "id": "db90a278", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "source": [ - "There are several ways of importing _modules_:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0f8ee4bb", + "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# import the whole module\n", - "import math\n", - "\n", - "# module's function name is in the module's namespace\n", - "print(math.sqrt(16.0))" + "## Bring all words to a common case" ] }, { "cell_type": "code", "execution_count": null, - "id": "338eca3f", + "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4995,34 +4515,31 @@ }, "outputs": [], "source": [ - "# import several modules at once\n", - "import pathlib, sys, time" + "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", + "print(arc_update)\n", + "print(arc_update.upper())\n", + "print(arc_update.title())\n", + "print(arc_update.capitalize())" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "2f29773e", + "cell_type": "markdown", + "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# use 'as' keyword to change the name of the module\n", - "import math as m\n", - "print(m.sqrt(36.0))" + "## Removing white space" ] }, { "cell_type": "code", "execution_count": null, - "id": "77b96e95", + "id": "22763b5f-7576-43c5-a237-925dce9b88aa", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5030,37 +4547,30 @@ }, "outputs": [], "source": [ - "# import only a selected function from a module\n", - "from math import sqrt\n", - "\n", - "# the function's name is in the global namespace\n", - "print(sqrt(49))" + "user_input = \" john.doe@email.com \"\n", + "email = user_input.strip()\n", + "print(f\"Original: '{user_input}'\")\n", + "print(f\"Cleaned: '{email}'\")" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "ce4f29f0", + "cell_type": "markdown", + "id": "6cf8076f-8f50-49ae-b558-39336c323880", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# change the name of the function in the module\n", - "from math import sqrt as square_root\n", - "print(square_root(25))" + "## Extracting/concatenating the individual words or parts" ] }, { "cell_type": "code", "execution_count": null, - "id": "44c18b00", + "id": "1f26c482", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5068,160 +4578,172 @@ }, "outputs": [], "source": [ - "# import all functions, variables, and classes from a module into the global namespace\n", - "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", - "from math import *\n", - "print(int(sqrt(4.0)))" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "\n", + "# split by space\n", + "print(line.split())\n", + "\n", + "# split by word\n", + "print(line.split('jumped'))" ] }, { "cell_type": "markdown", - "id": "d1cc0855", + "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", "metadata": { - "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "source": [ - "---\n", - "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." + "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" ] }, { "cell_type": "code", "execution_count": null, - "id": "558e0d9e", + "id": "5c81a93d-6fca-40e5-ae22-6697a9352272", "metadata": { - "editable": true, "slideshow": { "slide_type": "" - } + }, + "tags": [] }, "outputs": [], "source": [ - "# get a list of the functions and variables in the module\n", - "dir(math)" + "string_list = [\"A\", \"list\", \"of\", \"split\", \"words\"]\n", + "print(\" \".join(string_list))" ] }, { "cell_type": "code", "execution_count": null, - "id": "01d2c703", + "id": "cb9837fc-dd67-447c-b503-8029678581ab", "metadata": { - "editable": true, "slideshow": { "slide_type": "" - } + }, + "tags": [] }, "outputs": [], "source": [ - "# get a long description\n", - "help(math)" - ] - }, - { - "cell_type": "markdown", - "id": "8e33b8e3", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "---" + "line_list = [\"First line\", \"Second line\"]\n", + "print(\"\\n\".join(line_list))" ] }, { "cell_type": "markdown", - "id": "2d186e61-b776-483a-a6b9-0890af512e80", + "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "# 8. Advanced string manipulation" + "## Have a play!" ] }, { "cell_type": "markdown", - "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", + "id": "a2cd1c9a-967b-4f4b-8153-c4f55d50b377", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ - "* Adjusting case\n", - "* Formatting strings\n", - " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", - "* Quering the existence, replacing, splitting" - ] - }, - { - "cell_type": "markdown", - "id": "00e14678-81a2-4509-815a-53f9f2fdb332", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "## Finding values \n", - "* `find()` and `index()` both return index of a substring,\n", - " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", - " - `find()` returns `-1` when a values was not found\n" + "### Practical Example: Text Processing Pipeline\n", + "\n", + "Let's combine several string manipulation techniques to clean and process some messy user data" ] }, { "cell_type": "code", "execution_count": null, - "id": "0eab0a2d-eea9-4c33-b700-56eb293ef28b", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, + "id": "3639015f-81e0-4abf-a574-0b2f1d08181b", + "metadata": {}, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "print(line.find('fox'))\n", - "print(line.index('fox'))" + "# Raw user input with various issues\n", + "user_data = [\n", + " \" john.doe@email.com \",\n", + " \"JANE SMITH \",\n", + " \" Bob_Wilson@test.co.uk \",\n", + " \"invalid-email-format\",\n", + " \" Sarah.Connor@future.net \"\n", + "]\n", + "\n", + "print(\"=== Text Processing Pipeline ===\")\n", + "print(\"Original data:\")\n", + "for i, item in enumerate(user_data, 1):\n", + " print(f\"{i}. '{item}'\")\n", + "\n", + "print(\"\\nProcessed data:\")\n", + "valid_emails = []\n", + "\n", + "for i, entry in enumerate(user_data, 1):\n", + " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", + " # Step 1: Remove whitespace\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 1 command)\n", + " \n", + " print(f\" After strip(): '{cleaned}'\")\n", + " \n", + " # Step 2: Handle different formats\n", + " if \"<\" in cleaned and \">\" in cleaned:\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 1 command)\n", + " \n", + " print(f\" Extracted from brackets: '{email_part}'\")\n", + " else:\n", + " email_part = cleaned\n", + " print(f\" No brackets found, using as-is\")\n", + " \n", + " # Basic email validation\n", + " if \"@\" in email_part and \".\" in email_part:\n", + " # Step 3: Normalize to lowercase\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 2 commands)\n", + "\n", + " print(f\" โœ“ Valid email: {normalized}\")\n", + " else:\n", + " print(f\" โœ— Invalid: {email_part}\")\n", + "\n", + "print(f\"\\n=== Results ===\")\n", + "print(f\"Found {len(valid_emails)} valid emails:\")\n", + "for email in valid_emails:\n", + " print(f\" - {email}\")\n", + "\n", + "# Bonus: Extract unique domains\n", + "# TODO: WRITE YOUR SOLUTION HERE\n", + "#... (hint: use for loop as we have a list of emails)\n", + "\n", + "print(f\"\\nUnique domains found: {sorted(domains)}\")" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "134c6eba-8897-4ee8-a6e5-f3740a0a4d21", + "cell_type": "markdown", + "id": "9fb3a479-cddd-4b00-8e5d-88194c82f9ed", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, - "outputs": [], "source": [ - "print(line.find('wombat'))" + "#### Solution" ] }, { "cell_type": "code", "execution_count": null, - "id": "fc5a28ef-8a31-434a-a653-1662cc274945", + "id": "d69d4356-f129-40c7-a682-2f2f5fb9d190", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -5229,129 +4751,158 @@ }, "outputs": [], "source": [ - "try:\n", - " print(line.index('wombat'))\n", - "except ValueError:\n", - " print(\"A wombat isn't mentioned in the text\")" - ] - }, - { - "cell_type": "markdown", - "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "## Checking conditions on strings" - ] - }, - { + "# Raw user input with various issues\n", + "user_data = [\n", + " \" john.doe@email.com \",\n", + " \"JANE SMITH \",\n", + " \" Bob_Wilson@test.co.uk \",\n", + " \"invalid-email-format\",\n", + " \" Sarah.Connor@future.net \"\n", + "]\n", + "\n", + "print(\"=== Text Processing Pipeline ===\")\n", + "print(\"Original data:\")\n", + "for i, item in enumerate(user_data, 1):\n", + " print(f\"{i}. '{item}'\")\n", + "\n", + "print(\"\\nProcessed data:\")\n", + "valid_emails = []\n", + "\n", + "for i, entry in enumerate(user_data, 1):\n", + " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", + " \n", + " # Step 1: Remove whitespace\n", + " cleaned = entry.strip()\n", + " print(f\" After strip(): '{cleaned}'\")\n", + " \n", + " # Step 2: Handle different formats\n", + " if \"<\" in cleaned and \">\" in cleaned:\n", + " # Extract email from \"Name \" format\n", + " email_part = cleaned.split(\"<\")[1].split(\">\")[0]\n", + " print(f\" Extracted from brackets: '{email_part}'\")\n", + " else:\n", + " email_part = cleaned\n", + " print(f\" No brackets found, using as-is\")\n", + " \n", + " # Step 3: Basic email validation\n", + " if \"@\" in email_part and \".\" in email_part:\n", + " # Step 4: Normalize to lowercase\n", + " normalized = email_part.lower()\n", + " valid_emails.append(normalized)\n", + " print(f\" โœ“ Valid email: {normalized}\")\n", + " else:\n", + " print(f\" โœ— Invalid: {email_part}\")\n", + "\n", + "print(f\"\\n=== Results ===\")\n", + "print(f\"Found {len(valid_emails)} valid emails:\")\n", + "for email in valid_emails:\n", + " print(f\" - {email}\")\n", + "\n", + "# Bonus: Extract unique domains\n", + "domains = {email.split('@')[1] for email in valid_emails}\n", + "print(f\"\\nUnique domains found: {sorted(domains)}\")" + ] + }, + { "cell_type": "markdown", - "id": "7b5ac28b-5cfb-4c43-bf54-093c240cbe2b", + "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, "source": [ - "* Checking whether a string starts or ends a certain way is really common and easy" + "# 8. (Optional) Working with modules: Examples and creating your own" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "77d4d329-9e07-4100-a84e-bd8e55287b5d", + "cell_type": "markdown", + "id": "b14a6818", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "\n", - "print(line.startswith('the')) # True\n", - "print(line.endswith('dog')) # True - makes sense!\n", - "print(line.endswith('fox')) # False - now it's clear why" + "## Some useful _modules_" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7e401e7c-4cc2-4de7-8e11-45654b9592b9", + "cell_type": "markdown", + "id": "012efab2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, - "outputs": [], "source": [ - "# Case sensitivity matters\n", - "print(line.startswith('The')) # False - capital T\n", - "print(line.startswith('the')) # True - lowercase t" + "Python comes with a program called _pip_ (Python Package Installer) which will automatically fetch packages released and listed on PyPI: `pip install `" ] }, { "cell_type": "markdown", - "id": "e040bf97-a6bd-493e-b047-2041b5a99131", + "id": "eb000d98", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "* The canonical way to search a string (if not interested in the index):" + "| Name | Description |\n", + "|------------------|-------------|\n", + "| **`time`** | functions for dealing with time\n", + "| **`datetime`** | allows to work with dates and times together\n", + "| **`os`** | functions for working with files, directories and operating system (lowlevel)\n", + "| **`pathlib`** | Classes for working with paths, files and directories in a higher level implementation\n", + "| **`shutils`** | contains a function to copy files\n", + "| **`sys`** | contains a function to quit your program\n", + "| **`zipfile`** | allows to compress/extract files or directory of files into/from a zip file\n", + "| **`urllib`** | allows to get files from the internet\n", + "| **`math`** | math functions such as `sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `floor`, `ceil` |\n", + "| **`numpy`** | fundamental package for scientific computing (a multidimensional array object; routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting; basic linear algebra, basic statistical operations, random simulation and much more) |\n", + "| **`scipy`** | a collection of mathematical algorithms and convenience functions built on the NumPy extension (high-level commands and classes for the manipulation and visualization of data) |\n", + "| **`matplotlib`** | library for plotting\n", + "| **`sympy`** | symbolic computations\n", + "| **`itertools`** | provides a generator-like object named `permutations`\n", + "| **`csv`** | parsing and writing `csv` files" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "47c2d357", + "cell_type": "markdown", + "id": "4e16a864", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "if \"fox\" in line:\n", - " print(\"A fox has been seen\")" + "## Using _modules_" ] }, { "cell_type": "markdown", - "id": "fe3ce02d-08bd-4c52-a935-d27b843dde39", + "id": "17798548", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "## Replacing a value:" + "### _Example_\n", + "Interfacing with the files: **`pathlib`**" ] }, { "cell_type": "code", "execution_count": null, - "id": "292d8b56-1142-4927-9320-9c6331f5a962", + "id": "cf38baf4-5486-4c17-bc93-42510f8a6db7", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5359,151 +4910,150 @@ }, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "print(line)\n", - "print(line.replace('brown', 'red'))" + "from pathlib import Path\n", + "# Create a Path object for the current directory\n", + "current_directory = Path('.')" ] }, { - "cell_type": "markdown", - "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", + "cell_type": "code", + "execution_count": null, + "id": "47affbe3-0eb6-4ed6-8717-3ef05b072a80", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, + "outputs": [], "source": [ - "## Bring all words to a common case" + "# list all ipynb files in the current directory\n", + "for file in current_directory.glob('*.ipynb'):\n", + " print(file.name)" ] }, { "cell_type": "code", "execution_count": null, - "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", + "id": "98714766-5033-43d8-a9a3-0589b7bf32ec", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", - "print(arc_update)\n", - "print(arc_update.upper())\n", - "print(arc_update.title())\n", - "print(arc_update.capitalize())" + "# We can also list all files in the current directory\n", + "for file in current_directory.iterdir():\n", + " print(file.name)" ] }, { - "cell_type": "markdown", - "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", + "cell_type": "code", + "execution_count": null, + "id": "3fe290ad-e12f-4021-b8ef-a6d9bd6a7467", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, + "outputs": [], "source": [ - "## Removing white space" + "# go to subfolders and files in these folders using /\n", + "file_path = current_directory / 'data' / 'data_file.txt'\n", + "\n", + "# check whether a file exists\n", + "if file_path.exists():\n", + " print(f\"The file {file_path} exists.\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "22763b5f-7576-43c5-a237-925dce9b88aa", + "id": "cdcbc0b1-197d-4fc5-95e9-9501868b7525", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "user_input = \" john.doe@email.com \"\n", - "email = user_input.strip()\n", - "print(f\"Original: '{user_input}'\")\n", - "print(f\"Cleaned: '{email}'\")" + "# Create a new test folder\n", + "new_folder = current_directory / 'test_folder'\n", + "new_folder.mkdir(exist_ok=True) # exist_ok=True prevents error if folder already exists" ] }, { - "cell_type": "markdown", - "id": "6cf8076f-8f50-49ae-b558-39336c323880", + "cell_type": "code", + "execution_count": null, + "id": "b33c4e26-ec82-405d-97a5-bd88488c06d8", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, + "outputs": [], "source": [ - "## Extracting/concatenating the individual words or parts" + "# Write text to a file in test_folder\n", + "output = \"This is some output\\nSecond line!\"\n", + "output_file = new_folder / 'output.txt'\n", + "output_file.write_text(output)" ] }, { "cell_type": "code", "execution_count": null, - "id": "1f26c482", + "id": "89847e34-7e99-4b89-904f-b7ec2c8dd774", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "\n", - "# split by space\n", - "print(line.split())\n", - "\n", - "# split by word\n", - "print(line.split('jumped'))" + "# Read back the content from the file we just created\n", + "content = output_file.read_text() # Read from the same file we created\n", + "print(\"Content of the file we just created:\")\n", + "print(content)" ] }, { "cell_type": "markdown", - "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", + "id": "4e9801e0", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, "source": [ - "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" + "---\n", + "We'll demonstrate how to use modules in the actual code using the example of reading/writing files. In the _Beginner_ course, we showed the basic reading/writing files using the built-in functions of Python. But there's a better way of doing that by means of the specialised module called **`csv`**." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "5c81a93d-6fca-40e5-ae22-6697a9352272", + "cell_type": "markdown", + "id": "a306f3cb", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, - "outputs": [], "source": [ - "string_list = [\"A\", \"list\", \"of\", \"split\", \"words\"]\n", - "print(\" \".join(string_list))" + "Writing a csv file:" ] }, { "cell_type": "code", "execution_count": null, - "id": "cb9837fc-dd67-447c-b503-8029678581ab", + "id": "b10a1b92", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5511,452 +5061,439 @@ }, "outputs": [], "source": [ - "line_list = [\"First line\", \"Second line\"]\n", - "print(\"\\n\".join(line_list))" + "import csv, math\n", + "\n", + "# Read the file object\n", + "with open(\"example.csv\", 'w') as out_f:\n", + " # use csv.writer to interact\n", + " writer = csv.writer(out_f, delimiter=',')\n", + " # write the headings\n", + " writer.writerow([\"x_axis\", \"y_axis\"])\n", + " # generate the data for x\n", + " x_axis = [x * 0.1 for x in range(0, 100)]\n", + " # write x and cos(x) for every entry\n", + " for x in x_axis:\n", + " writer.writerow([x, math.cos(x)])\n", + "\n", + "print(\"Created example.csv with x and cos(x) values\")" ] }, { "cell_type": "markdown", - "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", + "id": "3a9c7b35", "metadata": { - "editable": true, + "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "## Have a play!" + "---\n", + "Now, letโ€™s extract the value for `y_axis` when `x_axis` is `1.0` for the csv we just wrote:" ] }, { - "cell_type": "markdown", - "id": "a2cd1c9a-967b-4f4b-8153-c4f55d50b377", + "cell_type": "code", + "execution_count": null, + "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "### Practical Example: Text Processing Pipeline\n", - "\n", - "Let's combine several string manipulation techniques to clean and process some messy user data" + "# Show the first few lines to demonstrate what we created\n", + "print(\"First few lines of the file:\")\n", + "with open(\"example.csv\", 'r') as f:\n", + " for _ in range(5):\n", + " print(f.readline().strip())" ] }, { "cell_type": "code", "execution_count": null, - "id": "3639015f-81e0-4abf-a574-0b2f1d08181b", - "metadata": {}, + "id": "9af8c87f-62db-4a04-86d8-d51428395210", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ - "# Raw user input with various issues\n", - "user_data = [\n", - " \" john.doe@email.com \",\n", - " \"JANE SMITH \",\n", - " \" Bob_Wilson@test.co.uk \",\n", - " \"invalid-email-format\",\n", - " \" Sarah.Connor@future.net \"\n", - "]\n", - "\n", - "print(\"=== Text Processing Pipeline ===\")\n", - "print(\"Original data:\")\n", - "for i, item in enumerate(user_data, 1):\n", - " print(f\"{i}. '{item}'\")\n", - "\n", - "print(\"\\nProcessed data:\")\n", - "valid_emails = []\n", - "\n", - "for i, entry in enumerate(user_data, 1):\n", - " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", - " # Step 1: Remove whitespace\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 1 command)\n", - " \n", - " print(f\" After strip(): '{cleaned}'\")\n", - " \n", - " # Step 2: Handle different formats\n", - " if \"<\" in cleaned and \">\" in cleaned:\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 1 command)\n", - " \n", - " print(f\" Extracted from brackets: '{email_part}'\")\n", - " else:\n", - " email_part = cleaned\n", - " print(f\" No brackets found, using as-is\")\n", - " \n", - " # Basic email validation\n", - " if \"@\" in email_part and \".\" in email_part:\n", - " # Step 3: Normalize to lowercase\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 2 commands)\n", - "\n", - " print(f\" โœ“ Valid email: {normalized}\")\n", - " else:\n", - " print(f\" โœ— Invalid: {email_part}\")\n", - "\n", - "print(f\"\\n=== Results ===\")\n", - "print(f\"Found {len(valid_emails)} valid emails:\")\n", - "for email in valid_emails:\n", - " print(f\" - {email}\")\n", - "\n", - "# Bonus: Extract unique domains\n", - "# TODO: WRITE YOUR SOLUTION HERE\n", - "#... (hint: use for loop as we have a list of emails)\n", - "\n", - "print(f\"\\nUnique domains found: {sorted(domains)}\")" + "# Show the value of Y for X==1.0 saved in the file\n", + "print(\"The value of Y for X==1.0 saved in the file:\")\n", + "with open (\"example.csv\", 'r') as in_f:\n", + " reader = csv.reader(in_f, delimiter=',')\n", + " next(reader) # skip header\n", + " for row in reader:\n", + " if row[0] == \"1.0\":\n", + " print(row[1])\n", + " break" ] }, { "cell_type": "markdown", - "id": "9fb3a479-cddd-4b00-8e5d-88194c82f9ed", + "id": "6ee8121a", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ - "#### Solution" + "---" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "d69d4356-f129-40c7-a682-2f2f5fb9d190", + "cell_type": "markdown", + "id": "a00f019b", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "all", "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# Raw user input with various issues\n", - "user_data = [\n", - " \" john.doe@email.com \",\n", - " \"JANE SMITH \",\n", - " \" Bob_Wilson@test.co.uk \",\n", - " \"invalid-email-format\",\n", - " \" Sarah.Connor@future.net \"\n", - "]\n", - "\n", - "print(\"=== Text Processing Pipeline ===\")\n", - "print(\"Original data:\")\n", - "for i, item in enumerate(user_data, 1):\n", - " print(f\"{i}. '{item}'\")\n", + "## Building your own module\n", "\n", - "print(\"\\nProcessed data:\")\n", - "valid_emails = []\n", + " - If you have a .py file in a path that is available to python, you can import any object defined in that file.\n", + " - If you have `mymodule.py` in your folder you can just write:\n", "\n", - "for i, entry in enumerate(user_data, 1):\n", - " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", - " \n", - " # Step 1: Remove whitespace\n", - " cleaned = entry.strip()\n", - " print(f\" After strip(): '{cleaned}'\")\n", - " \n", - " # Step 2: Handle different formats\n", - " if \"<\" in cleaned and \">\" in cleaned:\n", - " # Extract email from \"Name \" format\n", - " email_part = cleaned.split(\"<\")[1].split(\">\")[0]\n", - " print(f\" Extracted from brackets: '{email_part}'\")\n", - " else:\n", - " email_part = cleaned\n", - " print(f\" No brackets found, using as-is\")\n", - " \n", - " # Step 3: Basic email validation\n", - " if \"@\" in email_part and \".\" in email_part:\n", - " # Step 4: Normalize to lowercase\n", - " normalized = email_part.lower()\n", - " valid_emails.append(normalized)\n", - " print(f\" โœ“ Valid email: {normalized}\")\n", - " else:\n", - " print(f\" โœ— Invalid: {email_part}\")\n", + " `import mymodule`\n", "\n", - "print(f\"\\n=== Results ===\")\n", - "print(f\"Found {len(valid_emails)} valid emails:\")\n", - "for email in valid_emails:\n", - " print(f\" - {email}\")\n", + " and use a function defined in there with `mymodule.my_function(arg)`\n", + " - of course you can also use the method\n", "\n", - "# Bonus: Extract unique domains\n", - "domains = {email.split('@')[1] for email in valid_emails}\n", - "print(f\"\\nUnique domains found: {sorted(domains)}\")" + " `from mymodule import my_function`" ] }, { "cell_type": "markdown", - "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", + "id": "dd9284d3-b9cc-43b1-a369-731c3e09351e", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "# 9. (Optional) Working with modules: Examples and creating your own" + "### Simple example:" ] }, { "cell_type": "markdown", - "id": "b14a6818", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, + "id": "9bdac1cc-4bdc-4a40-b4d7-25e24edc611f", + "metadata": {}, "source": [ - "## Some useful _modules_" + "Create a file called `calculator.py`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d4973db-7dbb-4a57-a027-d12de35c9d48", + "metadata": {}, + "outputs": [], + "source": [ + "module_path = 'calculator.py'\n", + "\n", + "module_content = \\\n", + "\"\"\"def add(a, b):\n", + " return a + b\n", + "\n", + "def multiply(a, b):\n", + " return a * b\n", + "\n", + "PI = 3.14159\n", + "\"\"\"\n", + "\n", + "with open(module_path, 'w') as fobj:\n", + " fobj.write(module_content)" ] }, { "cell_type": "markdown", - "id": "012efab2", + "id": "a547c272-803a-46e8-af1f-00600ad11e92", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ - "Python comes with a program called _pip_ (Python Package Installer) which will automatically fetch packages released and listed on PyPI: `pip install `" + "Then you can use it in your main program:" ] }, { - "cell_type": "markdown", - "id": "eb000d98", + "cell_type": "code", + "execution_count": null, + "id": "2d3584bd-f99b-4fc8-9b19-db321634f329", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "| Name | Description |\n", - "|------------------|-------------|\n", - "| **`time`** | functions for dealing with time\n", - "| **`datetime`** | allows to work with dates and times together\n", - "| **`os`** | functions for working with files, directories and operating system (lowlevel)\n", - "| **`pathlib`** | Classes for working with paths, files and directories in a higher level implementation\n", - "| **`shutils`** | contains a function to copy files\n", - "| **`sys`** | contains a function to quit your program\n", - "| **`zipfile`** | allows to compress/extract files or directory of files into/from a zip file\n", - "| **`urllib`** | allows to get files from the internet\n", - "| **`math`** | math functions such as `sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `floor`, `ceil` |\n", - "| **`numpy`** | fundamental package for scientific computing (a multidimensional array object; routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting; basic linear algebra, basic statistical operations, random simulation and much more) |\n", - "| **`scipy`** | a collection of mathematical algorithms and convenience functions built on the NumPy extension (high-level commands and classes for the manipulation and visualization of data) |\n", - "| **`matplotlib`** | library for plotting\n", - "| **`sympy`** | symbolic computations\n", - "| **`itertools`** | provides a generator-like object named `permutations`\n", - "| **`csv`** | parsing and writing `csv` files" + "import calculator\n", + "\n", + "result = calculator.add(5, 3)\n", + "print(f\"5 + 3 = {result}\")\n", + "print(f\"Pi is approximately {calculator.PI}\")" ] }, { "cell_type": "markdown", - "id": "4e16a864", + "id": "47dd6a0c", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "## Using _modules_" + "### ```__main__``` special built-in variable\n", + "**Important:** When creating modules, you need to be careful about code that runs automatically. So, python files can be executed with `python mymodule.py` or loaded from with `import`.\n", + "However, all commands just put into a python file will be executed on import.\n", + "\n", + "The answer is to introduce a `__main__` block that is only executed when the file is called as a script.\n", + "It is good practice to have all code executed in a script to be either in a function or in this block." ] }, { "cell_type": "markdown", - "id": "17798548", + "id": "7f4123ae", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, "source": [ - "### _Example_\n", - "Interfacing with the files: **`pathlib`**" + "\n", + "### Example content of `mymodule.py`:\n", + "```python\n", + "def myfunction():\n", + " print(\"I will be only printed when the function is called\")\n", + "\n", + "print(\"I will be called on import and execution as a script\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(\"I will only executed when called as a script\")\n", + "```" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "cf38baf4-5486-4c17-bc93-42510f8a6db7", + "cell_type": "markdown", + "id": "bbe2196d", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "from pathlib import Path\n", - "# Create a Path object for the current directory\n", - "current_directory = Path('.')" - ] - }, - { + "## Have a play!\n", + "\n", + "**Exercise: Create and use your own module**\n", + "\n", + "1. **Create the module file**: Put the example content from the previous slide into a `mymodule.py` file in your folder\n", + "2. **Import and test**: Import `myfunction` into this notebook and run it\n", + "3. **Observe the output**: Notice what gets printed when you import the module\n", + "4. **Add functionality**: Create a new function that returns the sine of a value\n", + " - *Note: You might need to restart the kernel (Kernel โ†’ Restart Kernel) if you've already imported the module*\n", + "5. **Test your addition**: Import the updated module and test your sine function\n", + "\n", + "**Goal**: Understand how modules work, what code runs on import, and how to add your own functions." + ] + }, + { "cell_type": "code", "execution_count": null, - "id": "47affbe3-0eb6-4ed6-8717-3ef05b072a80", + "id": "be842bd3", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# list all ipynb files in the current directory\n", - "for file in current_directory.glob('*.ipynb'):\n", - " print(file.name)" + "# solution hint, cell 1\n", + "# (In the solution writing to a module is done as code in this cell)\n", + "# Write the content into the module file:\n", + "\n", + "module_path = 'mymodule.py'\n", + "\n", + "module_content = \\\n", + "\"\"\"def myfunction():\n", + " print(\"I will be only printed when the function is called\")\n", + "\n", + "print(\"I will be called on import and execution as a script\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(\"I will only executed when called as a script\")\n", + "\"\"\"\n", + "\n", + "with open(module_path, 'w') as fobj:\n", + " fobj.write(module_content)" ] }, { "cell_type": "code", "execution_count": null, - "id": "98714766-5033-43d8-a9a3-0589b7bf32ec", + "id": "506cd6b2", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# We can also list all files in the current directory\n", - "for file in current_directory.iterdir():\n", - " print(file.name)" + "# solution hint, cell 2\n", + "# Import the module:\n", + "import mymodule" ] }, { "cell_type": "code", "execution_count": null, - "id": "3fe290ad-e12f-4021-b8ef-a6d9bd6a7467", + "id": "454b088a", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# go to subfolders and files in these folders using /\n", - "file_path = current_directory / 'data' / 'data_file.txt'\n", - "\n", - "# check whether a file exists\n", - "if file_path.exists():\n", - " print(f\"The file {file_path} exists.\")" + "# solution hint, cell 3\n", + "# Call the function from the module:\n", + "mymodule.myfunction()" ] }, { "cell_type": "code", "execution_count": null, - "id": "cdcbc0b1-197d-4fc5-95e9-9501868b7525", + "id": "faee9ea4", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# Create a new test folder\n", - "new_folder = current_directory / 'test_folder'\n", - "new_folder.mkdir(exist_ok=True) # exist_ok=True prevents error if folder already exists" + "# solution hint, cell 4\n", + "# (In the solution writing to a module is done as code in this cell)\n", + "# To avoid the kernel restart, we output into a second file:\n", + "module_path = 'mymodule2.py'\n", + "\n", + "module_content2 = \\\n", + "\"\"\"import math\n", + "\n", + "def useless_sine(value):\n", + " return math.sin(value)\n", + "\n", + "def myfunction():\n", + " print(\"I will be only printed when the function is called\")\n", + "\n", + "print(\"I will be called on import and execution as a script\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(\"I will only executed when called as a script\")\n", + "\"\"\"\n", + "\n", + "with open(module_path, 'w') as fobj:\n", + " fobj.write(module_content2)" ] }, { "cell_type": "code", "execution_count": null, - "id": "b33c4e26-ec82-405d-97a5-bd88488c06d8", + "id": "c8b612fa", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# Write text to a file in test_folder\n", - "output = \"This is some output\\nSecond line!\"\n", - "output_file = new_folder / 'output.txt'\n", - "output_file.write_text(output)" + "# solution hint, cell 4\n", + "# Import your module and run the sine function from your own module:\n", + "import mymodule2\n", + "mymodule2.useless_sine(1.57)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "89847e34-7e99-4b89-904f-b7ec2c8dd774", + "cell_type": "markdown", + "id": "9e01e73d", "metadata": { - "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# Read back the content from the file we just created\n", - "content = output_file.read_text() # Read from the same file we created\n", - "print(\"Content of the file we just created:\")\n", - "print(content)" + "# 9. (Optional) Brief introduction to Object-Oriented Programming" ] }, { "cell_type": "markdown", - "id": "4e9801e0", + "id": "3627c2ef", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "---\n", - "We'll demonstrate how to use modules in the actual code using the example of reading/writing files. In the _Beginner_ course, we showed the basic reading/writing files using the built-in functions of Python. But there's a better way of doing that by means of the specialised module called **`csv`**." + "* Python is an object oriented programming language. Object-Oriented Programming (OOP) is a programming paradigm based on the concept of \"objects\" which can contain:\n", + " - Data (attributes)\n", + " - Code (methods)" ] }, { "cell_type": "markdown", - "id": "a306f3cb", + "id": "8393fae9", "metadata": { - "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, "tags": [] }, "source": [ - "Writing a csv file:" + "\n", + "## 1. Classes and Objects\n", + " - Class: A blueprint for creating objects (Think a cookiecutter)\n", + " - Object: An instance of a class (The created cookies)\n", + "\n", + "\n", + "A simple example:" ] }, { "cell_type": "code", "execution_count": null, - "id": "b10a1b92", + "id": "5005c5bc", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5964,65 +5501,58 @@ }, "outputs": [], "source": [ - "import csv, math\n", + "# Simple example\n", + "class CourseParticipant:\n", + " def __init__(self, name, email):\n", + " self.name = name\n", + " self.email = email\n", "\n", - "# Read the file object\n", - "with open(\"example.csv\", 'w') as out_f:\n", - " # use csv.writer to interact\n", - " writer = csv.writer(out_f, delimiter=',')\n", - " # write the headings\n", - " writer.writerow([\"x_axis\", \"y_axis\"])\n", - " # generate the data for x\n", - " x_axis = [x * 0.1 for x in range(0, 100)]\n", - " # write x and cos(x) for every entry\n", - " for x in x_axis:\n", - " writer.writerow([x, math.cos(x)])\n", + " def welcome(self):\n", + " print(f\"Welcome {self.name}! We're glad to have you.\")\n", "\n", - "print(\"Created example.csv with x and cos(x) values\")" + "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", + "participant1.welcome()" ] }, { "cell_type": "markdown", - "id": "3a9c7b35", + "id": "d9003b8b", "metadata": { - "editable": true, - "jp-MarkdownHeadingCollapsed": true, "slideshow": { - "slide_type": "slide" + "slide_type": "notes" }, "tags": [] }, "source": [ - "---\n", - "Now, letโ€™s extract the value for `y_axis` when `x_axis` is `1.0` for the csv we just wrote:" + "Speaker notes:\n", + "\n", + "The parts are:\n", + "- `class ClassName`: Classes are created with the `class` keyword and named in CamelCase\n", + "- `def __init__...`: The constructor method. This is used to create a new instance (cookie), with a given set of input variables. The first one is the reference to a given object created from the class (`self`), which is used to store the data/state.\n", + "- `def method_name(self)`: A method name. We again use `self` as the reference to an object created from the class" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", + "cell_type": "markdown", + "id": "b2a91e2a", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# Show the first few lines to demonstrate what we created\n", - "print(\"First few lines of the file:\")\n", - "with open(\"example.csv\", 'r') as f:\n", - " for _ in range(5):\n", - " print(f.readline().strip())" + "## 2. Encapsulation\n", + " - Bundling data and methods that work on that data within one unit\n", + " - Restricting access to certain details\n", + " - Is also often used to keep track of states." ] }, { "cell_type": "code", "execution_count": null, - "id": "9af8c87f-62db-4a04-86d8-d51428395210", + "id": "74cd0847", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -6030,120 +5560,191 @@ }, "outputs": [], "source": [ - "# Show the value of Y for X==1.0 saved in the file\n", - "print(\"The value of Y for X==1.0 saved in the file:\")\n", - "with open (\"example.csv\", 'r') as in_f:\n", - " reader = csv.reader(in_f, delimiter=',')\n", - " next(reader) # skip header\n", - " for row in reader:\n", - " if row[0] == \"1.0\":\n", - " print(row[1])\n", - " break" + "class CourseParticipant:\n", + " def __init__(self, name, email):\n", + " self.name = name\n", + " self.email = email\n", + " self.registered_attendance = False\n", + "\n", + " def welcome(self):\n", + " print(f\"Welcome {self.name}! We're glad to have you.\")\n", + "\n", + " def register_attendance(self):\n", + " self.registered_attendance = True\n", + " print(f\"{self.name} has been registered for attendance.\")\n", + "\n", + "# use the class\n", + "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", + "participant1.welcome()\n", + "participant1.register_attendance()\n" ] }, { "cell_type": "markdown", - "id": "6ee8121a", + "id": "915e7f40", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "notes" }, "tags": [] }, "source": [ - "---" + "Speaker notes:\n", + " - Imagine we need a function to track whether users have attended the course.\n", + " - We can change the internal state of the object representing a given participant.\n", + " - By checking the registered_attendance attribute, we can track which participants have registered" ] }, { "cell_type": "markdown", - "id": "a00f019b", + "id": "df442469", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, "tags": [] }, "source": [ - "## Building your own module\n", - "\n", - " - If you have a .py file in a path that is available to python, you can import any object defined in that file.\n", - " - If you have `mymodule.py` in your folder you can just write:\n", - "\n", - " `import mymodule`\n", - "\n", - " and use a function defined in there with `mymodule.my_function(arg)`\n", - " - of course you can also use the method\n", - "\n", - " `from mymodule import my_function`" + "## 3. Inheritance\n", + " - Creating new classes that extend the functionality of existing classes\n", + " - We _inherit_ the properties of the base class `CourseParticipant`\n", + " - `super()` lets us invoke the function of the same name from the base class\n", + " - Carefully decide between inheritance and composition (see soon)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e94ff6d", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "class ExternalParticipant(CourseParticipant):\n", + " def __init__(self, name, email, company):\n", + " super().__init__(name, email)\n", + " self.company = company\n", + "\n", + " def contact_company(self):\n", + " print(f\"Contacting {self.company} regarding course participation.\")\n", + "\n", + "external_participant1 = ExternalParticipant(\"Bob\", \"bob@example.com\", \"Cooperative Inc.\")\n", + "external_participant1.welcome()\n", + "external_participant1.contact_company()\n" ] }, { "cell_type": "markdown", - "id": "dd9284d3-b9cc-43b1-a369-731c3e09351e", + "id": "206d9ee0", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "notes" }, "tags": [] }, "source": [ - "### Simple example:" + "Speaker notes:\n", + "\n", + "Now imagine we can have external participants that are affiliated with a company. We want our object to have all the functionality of our `CourseParticipant` class, but also have additional functionality that is specific to our external participants." ] }, { "cell_type": "markdown", - "id": "9bdac1cc-4bdc-4a40-b4d7-25e24edc611f", - "metadata": {}, + "id": "2cf3958b", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, "source": [ - "Create a file called `calculator.py`:" + "## 4. Polymorphism\n", + "- Definition: Call the same method name on different object types and get type-specific behavior.\n", + "- Key idea: Write code to an interface, not a concrete class.\n", + "- Why it matters:\n", + " - Decouples caller from concrete types (extensible)\n", + " - Removes conditionals/type-checks (cleaner)\n", + " - Eases testing and substitution (mocks/fakes)" ] }, { "cell_type": "code", "execution_count": null, - "id": "9d4973db-7dbb-4a57-a027-d12de35c9d48", - "metadata": {}, + "id": "a414bc89", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ - "module_path = 'calculator.py'\n", + "class DurhamUniversityParticipant(CourseParticipant):\n", + " def register_attendance(self):\n", + " super().register_attendance()\n", + " print(f\" Also registered attendance with the internal additional system for {self.name}\")\n", + " \n", "\n", - "module_content = \\\n", - "\"\"\"def add(a, b):\n", - " return a + b\n", + "participants = [\n", + " ExternalParticipant(\"Alice\", \"alice@example.com\", \"Acme Corp\"),\n", + " DurhamUniversityParticipant(\"Bob\", \"bob@durham.ac.uk\"),\n", + " CourseParticipant(\"Charlie\", \"charlie@example.com\")\n", + "]\n", "\n", - "def multiply(a, b):\n", - " return a * b\n", + "for participant in participants:\n", + " participant.register_attendance()" + ] + }, + { + "cell_type": "markdown", + "id": "5385bec2", + "metadata": { + "slideshow": { + "slide_type": "notes" + }, + "tags": [] + }, + "source": [ + "Speaker notes:\n", "\n", - "PI = 3.14159\n", - "\"\"\"\n", + "Say for registering the attendance for our internal participants we are also required to call an API function (represented by the print statement here). We can overwrite the function to behave differently for the `DurhamUniveristyParticipant` class\n", "\n", - "with open(module_path, 'w') as fobj:\n", - " fobj.write(module_content)" + " - We are using `super()` again. Note that this is not necessary\n", + " - We can still just use `register_attendance()` even though one of the functions now behaves differently.\n", + " - If there are lots of `if/else` statements depending on which type an programmed structure represents, objects with different types can simplify the structure significantly.\n", + " - It is quite easy to introduce an additional class that has another option for the behaviour." ] }, { "cell_type": "markdown", - "id": "a547c272-803a-46e8-af1f-00600ad11e92", + "id": "fdb800a8", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, "source": [ - "Then you can use it in your main program:" + "## 5. Composition\n", + "\n", + "- Definition: Build classes by combining other objects (a class has collaborators).\n", + "- Why choose it:\n", + " - Favors flexibility and reuse over tight inheritance ties\n", + " - Swap components easily\n", + "\n", + "- If your `__init__` functions have alternative optional parameters, this is often a sign you should use composition\n", + "- Especially favour composition if there are several options for different behaviours that can be combined interchangeably (_has-a_ vs interitance: _is-a_)\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "2d3584bd-f99b-4fc8-9b19-db321634f329", + "id": "2cea837b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -6151,144 +5752,188 @@ }, "outputs": [], "source": [ - "import calculator\n", + "class Messenger:\n", + " def send_message(self, message):\n", + " pass\n", "\n", - "result = calculator.add(5, 3)\n", - "print(f\"5 + 3 = {result}\")\n", - "print(f\"Pi is approximately {calculator.PI}\")" + "class EmailMessenger(Messenger):\n", + "\n", + " def __init__(self, email):\n", + " self.email = email\n", + "\n", + " def send_message(self, message):\n", + " print(f\"Sending email to {self.email}: {message}\")\n", + "\n", + "class TeamsMessenger(Messenger):\n", + "\n", + " def __init__(self, user_id):\n", + " self.user_id = user_id\n", + "\n", + " def send_message(self, message):\n", + " print(f\"Sending Teams message to {self.user_id}: {message}\")\n", + "\n", + "\n", + "class Participant:\n", + " def __init__(self, name, messenger):\n", + " self.name = name\n", + " self.messenger = messenger\n", + "\n", + " def welcome(self):\n", + " self.messenger.send_message(f\"Welcome {self.name}!\")\n", + "\n", + "# Use the Participant class\n", + "participants = [\n", + " Participant(\"Alice\", EmailMessenger(\"alice@example.com\")),\n", + " Participant(\"Bob\", TeamsMessenger(\"bob123\"))\n", + "]\n", + "\n", + "for participant in participants:\n", + " participant.welcome()\n" ] }, { "cell_type": "markdown", - "id": "47dd6a0c", + "id": "7ea0b8f0", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "notes" }, "tags": [] }, "source": [ - "### ```__main__``` special built-in variable\n", - "**Important:** When creating modules, you need to be careful about code that runs automatically. So, python files can be executed with `python mymodule.py` or loaded from with `import`.\n", - "However, all commands just put into a python file will be executed on import.\n", - "\n", - "The answer is to introduce a `__main__` block that is only executed when the file is called as a script.\n", - "It is good practice to have all code executed in a script to be either in a function or in this block." + "Speaker notes\n", + " - In this example, participants can be contacted via e-mail or Teams\n", + " - The information we need for the two contact possibilities is completely independent\n", + " - The specific behaviour is used by the class, but the details are not important for the class\n", + " - So each object `has-a` messenger that can be used to contact the participant\n", + " - It is straightforward to inherit the different participant classes (External / DU) using this messenger, without creating four (Messing (2) x DU/External (2)) classes that would be needed with inheritance also\n" ] }, { "cell_type": "markdown", - "id": "7f4123ae", + "id": "129df112", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "d9c8cd20", "metadata": { - "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, "tags": [] }, "source": [ - "\n", - "### Example content of `mymodule.py`:\n", - "```python\n", - "def myfunction():\n", - " print(\"I will be only printed when the function is called\")\n", - "\n", - "print(\"I will be called on import and execution as a script\")\n", - "\n", - "if __name__ == \"__main__\":\n", - " print(\"I will only executed when called as a script\")\n", - "```" + "## Have a play!" ] }, { "cell_type": "markdown", - "id": "bbe2196d", + "id": "4858e58f", "metadata": { - "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "notes" }, "tags": [] }, "source": [ - "## Have a play!\n", - "\n", - "**Exercise: Create and use your own module**\n", - "\n", - "1. **Create the module file**: Put the example content from the previous slide into a `mymodule.py` file in your folder\n", - "2. **Import and test**: Import `myfunction` into this notebook and run it\n", - "3. **Observe the output**: Notice what gets printed when you import the module\n", - "4. **Add functionality**: Create a new function that returns the sine of a value\n", - " - *Note: You might need to restart the kernel (Kernel โ†’ Restart Kernel) if you've already imported the module*\n", - "5. **Test your addition**: Import the updated module and test your sine function\n", + "Speaker notes:\n", "\n", - "**Goal**: Understand how modules work, what code runs on import, and how to add your own functions." + "While the explanations went quite a bit further, this example only needs the application of encapsulation. Packaging up basic Application Programming Interfaces (APIs) into a more useable form is a useful and common application of OOP. In the interest of time / scope we will keep the exercise a bit more simple, but feel free to also inquire about the other concepts while you work on it." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "be842bd3", + "cell_type": "markdown", + "id": "28e31e47", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", "slideshow": { "slide_type": "" }, "tags": [] }, - "outputs": [], "source": [ - "# solution hint, cell 1\n", - "# (In the solution writing to a module is done as code in this cell)\n", - "# Write the content into the module file:\n", + "### Plant Sensor API Exercise\n", + "You've been given a virtual sensor API module which you can import with (`import sensor_api`) that can monitor plants. \n", + "The API provides three functions:\n", "\n", - "module_path = 'mymodule.py'\n", + "- `connect(sensor_id)`: Connects to a sensor (returns True/False)\n", + "- `disconnect(sensor_id)`: Disconnects from a sensor (returns True/False) \n", + "- `send_message(message)`: Sends a command and receives a reading (returns float or None)\n", "\n", - "module_content = \\\n", - "\"\"\"def myfunction():\n", - " print(\"I will be only printed when the function is called\")\n", + "#### Message Format\n", + "Messages must be formatted as: `\"SENSOR_ID:COMMAND\"`\n", "\n", - "print(\"I will be called on import and execution as a script\")\n", + "Available commands:\n", + "- `SOIL_HUMIDITY`: Get soil humidity (0-100%)\n", + "- `AIR_HUMIDITY`: Get air humidity (0-100%)\n", + "- `TEMPERATURE`: Get temperature in Celsius\n", "\n", - "if __name__ == \"__main__\":\n", - " print(\"I will only executed when called as a script\")\n", - "\"\"\"\n", + "#### Before\n", + "This is how working with the API would currently look:\n", "\n", - "with open(module_path, 'w') as fobj:\n", - " fobj.write(module_content)" + "```python\n", + "import sensor_api\n", + "\n", + "sensor_id = \"GREENHOUSE_01\"\n", + "sensor_api.connect(sensor_id)\n", + "\n", + "soil_humidity = float(sensor_api.send_message(f\"{id}:SOIL_HUMIDITY\"))\n", + "air_humidity = float(sensor_api.send_message(f\"{id}:AIR_HUMIDITY\"))\n", + "temperature = float(sensor_api.send_message(f\"{id}:TEMPERATURE\"))\n", + "\n", + "print(f\"\\n=== Plant Sensor {sensor_id} Readings ===\")\n", + "print(f\"Soil Humidity: {soil_humidity}%\")\n", + "print(f\"Air Humidity: {air_humidity}%\")\n", + "print(f\"Temperature: {temperature}ยฐC\")\n", + "print(\"=\" * 35)\n", + "sensor_api.disconnect(id)\n", + "```\n", + "\n", + "#### Your Task\n", + "Create a `PlantSensor` class that:\n", + "\n", + "1. Stores the sensor ID when created\n", + "2. Automatically connects when initialized\n", + "3. Provides easy-to-use methods for each measurement type\n", + "4. Properly disconnects when done\n", + "5. Displays all readings in a nice format\n", + "\n", + "\n", + "\n", + "#### Desired result\n", + "```python\n", + "# This is how your class should work:\n", + "sensor = PlantSensor(\"PLANT_01\")\n", + "soil = sensor.get_soil_humidity()\n", + "air = sensor.get_air_humidity()\n", + "temp = sensor.get_temperature()\n", + "sensor.display_readings()\n", + "sensor.disconnect()\n", + "```" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "506cd6b2", + "cell_type": "markdown", + "id": "9cb57fee", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "# solution hint, cell 2\n", - "# Import the module:\n", - "import mymodule" + "### Implementation" ] }, { "cell_type": "code", "execution_count": null, - "id": "454b088a", + "id": "fb0d76f6", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", + "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -6296,58 +5941,71 @@ }, "outputs": [], "source": [ - "# solution hint, cell 3\n", - "# Call the function from the module:\n", - "mymodule.myfunction()" + "import sensor_api\n", + "\n", + "class PlantSensor:\n", + " def __init__(self, sensor_id):\n", + " \"\"\"Initialize the sensor with an ID and connect to it.\"\"\"\n", + " self.sensor_id = sensor_id\n", + " self.connected = sensor_api.connect(sensor_id)\n", + " \n", + " # Store readings\n", + " self.soil_humidity = None\n", + " self.air_humidity = None\n", + " self.temperature = None\n", + " \n", + " def get_soil_humidity(self):\n", + " \"\"\"Get soil humidity reading.\"\"\"\n", + " if self.connected:\n", + " message = f\"{self.sensor_id}:SOIL_HUMIDITY\"\n", + " self.soil_humidity = float(sensor_api.send_message(message))\n", + " return self.soil_humidity\n", + " return None\n", + " \n", + " def get_air_humidity(self):\n", + " \"\"\"Get air humidity reading.\"\"\"\n", + " if self.connected:\n", + " message = f\"{self.sensor_id}:AIR_HUMIDITY\"\n", + " self.air_humidity = float(sensor_api.send_message(message))\n", + " return self.air_humidity\n", + " return None\n", + " \n", + " def get_temperature(self):\n", + " \"\"\"Get temperature reading.\"\"\"\n", + " if self.connected:\n", + " message = f\"{self.sensor_id}:TEMPERATURE\"\n", + " self.temperature = float(sensor_api.send_message(message))\n", + " return self.temperature\n", + " return None\n", + " \n", + " def display_readings(self):\n", + " \"\"\"Display all sensor readings.\"\"\"\n", + " print(f\"\\n=== Plant Sensor {self.sensor_id} Readings ===\")\n", + " print(f\"Soil Humidity: {self.soil_humidity}%\")\n", + " print(f\"Air Humidity: {self.air_humidity}%\")\n", + " print(f\"Temperature: {self.temperature}ยฐC\")\n", + " print(\"=\" * 35)\n", + " \n", + " def disconnect(self):\n", + " \"\"\"Disconnect from the sensor.\"\"\"\n", + " if self.connected:\n", + " sensor_api.disconnect(self.sensor_id)\n", + " self.connected = False" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "faee9ea4", - "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], + "cell_type": "markdown", + "id": "1624a7a4", + "metadata": {}, "source": [ - "# solution hint, cell 4\n", - "# (In the solution writing to a module is done as code in this cell)\n", - "# To avoid the kernel restart, we output into a second file:\n", - "module_path = 'mymodule2.py'\n", - "\n", - "module_content2 = \\\n", - "\"\"\"import math\n", - "\n", - "def useless_sine(value):\n", - " return math.sin(value)\n", - "\n", - "def myfunction():\n", - " print(\"I will be only printed when the function is called\")\n", - "\n", - "print(\"I will be called on import and execution as a script\")\n", - "\n", - "if __name__ == \"__main__\":\n", - " print(\"I will only executed when called as a script\")\n", - "\"\"\"\n", - "\n", - "with open(module_path, 'w') as fobj:\n", - " fobj.write(module_content2)" + "You can use this to try to use your class. You can comment out functionality, if you have not implemented it yet" ] }, { "cell_type": "code", "execution_count": null, - "id": "c8b612fa", + "id": "49d66487", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", "slideshow": { "slide_type": "" }, @@ -6355,17 +6013,24 @@ }, "outputs": [], "source": [ - "# solution hint, cell 4\n", - "# Import your module and run the sine function from your own module:\n", - "import mymodule2\n", - "mymodule2.useless_sine(1.57)" + "my_plant = PlantSensor(\"GREENHOUSE_01\")\n", + "\n", + "# Take readings\n", + "my_plant.get_soil_humidity()\n", + "my_plant.get_air_humidity()\n", + "my_plant.get_temperature()\n", + "\n", + "# Display results\n", + "my_plant.display_readings()\n", + "\n", + "# Clean up\n", + "my_plant.disconnect()" ] }, { "cell_type": "markdown", "id": "6522c182", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" } @@ -6378,7 +6043,6 @@ "cell_type": "markdown", "id": "ef9b73ae", "metadata": { - "editable": true, "slideshow": { "slide_type": "slide" }, @@ -6416,7 +6080,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.12.3" } }, "nbformat": 4, From 45b3b5d07ead562b11aed1064b202cecf2ab707d Mon Sep 17 00:00:00 2001 From: Dmitry Nikolaenko Date: Thu, 26 Feb 2026 17:48:17 +0000 Subject: [PATCH 3/9] Improve advanced string manipulation section - Briefly explained methods of objects in the context of strings - Revised each subsection for better readability - Added a few examples demonstrating exceptions in the context of string manipulation - Modified slide types containing notes to 'skip' for student notebook generation (also outside of string manipulation, but not in classes as it's moved to the end in another issue) --- Intermediate.ipynb | 262 +++++++++++++++++++++++++++++------ Intermediate_full.ipynb | 296 +++++++++++++++++++++++++++++++++------- 2 files changed, 468 insertions(+), 90 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index b83adf6..15dd2b3 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -4749,6 +4749,62 @@ "# 8. Advanced string manipulation" ] }, + { + "cell_type": "markdown", + "id": "e34aedb6", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "## String Methods - Working with String Objects" + ] + }, + { + "cell_type": "markdown", + "id": "ffef8f84", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "In Python, strings are objects, and objects have **methods** - functions that belong to and operate on that object.\n", + "\n", + "**Syntax**: `string_object.method_name(arguments)`\n", + "\n", + "Key characteristics:\n", + "- Methods are called using _dot notation_: `variable.method()`\n", + "- String methods return a **new string** (strings are immutable)\n", + "- The original string is never modified\n", + "- You must assign the result if you want to keep it\n", + "\n", + "**Example:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5bd4280", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "text = \"hello world\"\n", + "result = text.upper() # Creates new string\n", + "print(text) # Still \"hello world\" \n", + "print(result) # \"HELLO WORLD\"" + ] + }, { "cell_type": "markdown", "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", @@ -4760,10 +4816,11 @@ "tags": [] }, "source": [ - "* Adjusting case\n", - "* Formatting strings\n", - " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", - "* Quering the existence, replacing, splitting" + "Common categories of string methods we'll explore:\n", + "- **Finding/searching**: `find()`, `index()`\n", + "- **Checking**: `startswith()`, `endswith()`\n", + "- **Transforming**: `replace()`, `upper()`, `lower()`, `capitalize()`, `strip()`\n", + "- **Splitting/joining**: `split()`, `join()`" ] }, { @@ -4777,10 +4834,22 @@ "tags": [] }, "source": [ - "## Finding values \n", - "* `find()` and `index()` both return index of a substring,\n", - " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", - " - `find()` returns `-1` when a values was not found\n" + "## Finding/searching string methods" + ] + }, + { + "cell_type": "markdown", + "id": "a4fa9b5b", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "These methods help you locate substrings within a string, returning their position or checking for their presence:\n", + "* `index()` - returns `-1` if the substring is not found\n", + "* `find()` - raises a `ValueError` if the substring is not found" ] }, { @@ -4817,6 +4886,19 @@ "print(line.find('wombat'))" ] }, + { + "cell_type": "markdown", + "id": "714fc569", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "The key difference is how they handle missing substrings - `find()` returns `-1` while `index()` raises an exception:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -4847,7 +4929,7 @@ "tags": [] }, "source": [ - "## Checking conditions on strings" + "## Checking string methods" ] }, { @@ -4861,7 +4943,9 @@ "tags": [] }, "source": [ - "* Checking whether a string starts or ends a certain way is really common and easy" + "These methods return boolean values (`True` or `False`) to verify if a string matches certain patterns or criteria:\n", + "* `startswith(substring)`\n", + "* `endswith(substring)`" ] }, { @@ -4908,12 +4992,12 @@ "metadata": { "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "* The canonical way to search a string (if not interested in the index):" + "The canonical way to search a string (if not interested in the index):" ] }, { @@ -4944,7 +5028,25 @@ "tags": [] }, "source": [ - "## Replacing a value:" + "## Transforming string methods" + ] + }, + { + "cell_type": "markdown", + "id": "80b12b8b", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "These methods create modified versions of strings by replacing content, changing case, or removing unwanted characters. _**Remember**: strings are immutable, so these methods always return a new string._\n", + "* `replace(old, new)`\n", + "* `upper()`\n", + "* `lower()`\n", + "* `capitalize()`\n", + "* `strip()`" ] }, { @@ -4966,23 +5068,29 @@ ] }, { - "cell_type": "markdown", - "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", + "cell_type": "code", + "execution_count": null, + "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", "metadata": { - "editable": false, + "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Bring all words to a common case" + "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", + "print(arc_update)\n", + "print(arc_update.upper())\n", + "print(arc_update.title())\n", + "print(arc_update.capitalize())" ] }, { "cell_type": "code", "execution_count": null, - "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", + "id": "22763b5f-7576-43c5-a237-925dce9b88aa", "metadata": { "editable": true, "slideshow": { @@ -4992,44 +5100,63 @@ }, "outputs": [], "source": [ - "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", - "print(arc_update)\n", - "print(arc_update.upper())\n", - "print(arc_update.title())\n", - "print(arc_update.capitalize())" + "user_input = \" john.doe@email.com \"\n", + "email = user_input.strip()\n", + "print(f\"Original: '{user_input}'\")\n", + "print(f\"Cleaned: '{email}'\")" ] }, { "cell_type": "markdown", - "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", + "id": "2fd63835", "metadata": { "editable": false, "slideshow": { "slide_type": "slide" - }, - "tags": [] + } }, "source": [ - "## Removing white space" + "These methods work with any string and don't raise exceptions, but you may want to validate the results." ] }, { "cell_type": "code", "execution_count": null, - "id": "22763b5f-7576-43c5-a237-925dce9b88aa", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, + "id": "8f1ceba1", + "metadata": {}, "outputs": [], "source": [ - "user_input = \" john.doe@email.com \"\n", - "email = user_input.strip()\n", - "print(f\"Original: '{user_input}'\")\n", - "print(f\"Cleaned: '{email}'\")" + "# Transforming methods don't raise exceptions, but you can validate transformed results\n", + "def process_username(username):\n", + " \"\"\"Process and validate a username.\"\"\"\n", + " if not isinstance(username, str):\n", + " raise TypeError(f\"Username must be a string, got {type(username).__name__}\")\n", + " \n", + " # Transform: strip whitespace and convert to lowercase\n", + " processed = username.strip().lower()\n", + " \n", + " # Validate the result\n", + " if not processed:\n", + " raise ValueError(\"Username cannot be empty after processing\")\n", + " \n", + " if len(processed) < 3:\n", + " raise ValueError(f\"Username must be at least 3 characters, got {len(processed)}\")\n", + " \n", + " return processed\n", + "\n", + "# Valid case\n", + "try:\n", + " result = process_username(\" JohnDoe \")\n", + " print(f\"\u2713 Processed username: '{result}'\")\n", + "except ValueError as e:\n", + " print(f\"Error: {e}\")\n", + "\n", + "# Invalid case\n", + "try:\n", + " result = process_username(\" AB \")\n", + " print(f\"\u2713 Processed username: '{result}'\")\n", + "except ValueError as e:\n", + " print(f\"Error: {e}\")" ] }, { @@ -5043,7 +5170,22 @@ "tags": [] }, "source": [ - "## Extracting/concatenating the individual words or parts" + "## Splitting/joining string methods" + ] + }, + { + "cell_type": "markdown", + "id": "71a4546c", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "These methods allow you to break strings apart into lists of substrings, or combine lists of strings into a single string. They're particularly useful for parsing text data or formatting output:\n", + "* `split(separator)` - splits string into a list at each occurrence of separator (defaults to whitespace)\n", + "* `join(iterable)` - joins elements of an iterable into a single string with the string as separator" ] }, { @@ -5079,7 +5221,7 @@ "tags": [] }, "source": [ - "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" + "The `join` operation is `a_string.join()` where `a_string` is placed between every string of a list" ] }, { @@ -5116,6 +5258,40 @@ "print(\"\\n\".join(line_list))" ] }, + { + "cell_type": "markdown", + "id": "0deaf239", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "`join()` will raise a `TypeError` if the iterable contains non-string elements" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "225bdd40", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "flags = [16384,1048576]\n", + "\n", + "for i in range(len(flags)):\n", + " flags_str = \"+\".join(flags[i])\n", + "#flags_str = \"+\".join(str(flag) for flag in flags)\n", + "#print(flags_str)" + ] + }, { "cell_type": "markdown", "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", @@ -5932,7 +6108,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.13.0" } }, "nbformat": 4, diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 3c33560..7e3148a 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -3318,7 +3318,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" } }, "source": [ @@ -3905,7 +3905,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" }, "tags": [] }, @@ -3963,7 +3963,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" }, "tags": [] }, @@ -4035,7 +4035,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" }, "tags": [] }, @@ -4094,7 +4094,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" }, "tags": [] }, @@ -4184,7 +4184,7 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "notes" + "slide_type": "skip" }, "tags": [] }, @@ -5148,6 +5148,62 @@ "# 8. Advanced string manipulation" ] }, + { + "cell_type": "markdown", + "id": "e34aedb6", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "## String Methods - Working with String Objects" + ] + }, + { + "cell_type": "markdown", + "id": "ffef8f84", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "In Python, strings are objects, and objects have **methods** - functions that belong to and operate on that object.\n", + "\n", + "**Syntax**: `string_object.method_name(arguments)`\n", + "\n", + "Key characteristics:\n", + "- Methods are called using _dot notation_: `variable.method()`\n", + "- String methods return a **new string** (strings are immutable)\n", + "- The original string is never modified\n", + "- You must assign the result if you want to keep it\n", + "\n", + "**Example:**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5bd4280", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "text = \"hello world\"\n", + "result = text.upper() # Creates new string\n", + "print(text) # Still \"hello world\" \n", + "print(result) # \"HELLO WORLD\"" + ] + }, { "cell_type": "markdown", "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", @@ -5159,10 +5215,11 @@ "tags": [] }, "source": [ - "* Adjusting case\n", - "* Formatting strings\n", - " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", - "* Quering the existence, replacing, splitting" + "Common categories of string methods we'll explore:\n", + "- **Finding/searching**: `find()`, `index()`\n", + "- **Checking**: `startswith()`, `endswith()`\n", + "- **Transforming**: `replace()`, `upper()`, `lower()`, `capitalize()`, `strip()`\n", + "- **Splitting/joining**: `split()`, `join()`" ] }, { @@ -5176,10 +5233,22 @@ "tags": [] }, "source": [ - "## Finding values \n", - "* `find()` and `index()` both return index of a substring,\n", - " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", - " - `find()` returns `-1` when a values was not found\n" + "## Finding/searching string methods" + ] + }, + { + "cell_type": "markdown", + "id": "a4fa9b5b", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "These methods help you locate substrings within a string, returning their position or checking for their presence:\n", + "* `index()` - returns `-1` if the substring is not found\n", + "* `find()` - raises a `ValueError` if the substring is not found" ] }, { @@ -5216,6 +5285,19 @@ "print(line.find('wombat'))" ] }, + { + "cell_type": "markdown", + "id": "714fc569", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "The key difference is how they handle missing substrings - `find()` returns `-1` while `index()` raises an exception:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -5246,7 +5328,7 @@ "tags": [] }, "source": [ - "## Checking conditions on strings" + "## Checking string methods" ] }, { @@ -5260,7 +5342,22 @@ "tags": [] }, "source": [ - "* Checking whether a string starts or ends a certain way is really common and easy" + "These methods return boolean values (`True` or `False`) to verify if a string matches certain patterns or criteria:\n", + "* `startswith(substring)`\n", + "* `endswith(substring)`" + ] + }, + { + "cell_type": "markdown", + "id": "6ac1c80f", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Note:** These methods are case-sensitive and never raise exceptions - they simply return `False` if the pattern doesn't match." ] }, { @@ -5307,12 +5404,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "* The canonical way to search a string (if not interested in the index):" + "The canonical way to search a string (if not interested in the index):" ] }, { @@ -5343,7 +5440,25 @@ "tags": [] }, "source": [ - "## Replacing a value:" + "## Transforming string methods" + ] + }, + { + "cell_type": "markdown", + "id": "80b12b8b", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "These methods create modified versions of strings by replacing content, changing case, or removing unwanted characters. _**Remember**: strings are immutable, so these methods always return a new string._\n", + "* `replace(old, new)`\n", + "* `upper()`\n", + "* `lower()`\n", + "* `capitalize()`\n", + "* `strip()`" ] }, { @@ -5365,23 +5480,29 @@ ] }, { - "cell_type": "markdown", - "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", + "cell_type": "code", + "execution_count": null, + "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", "metadata": { "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Bring all words to a common case" + "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", + "print(arc_update)\n", + "print(arc_update.upper())\n", + "print(arc_update.title())\n", + "print(arc_update.capitalize())" ] }, { "cell_type": "code", "execution_count": null, - "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", + "id": "22763b5f-7576-43c5-a237-925dce9b88aa", "metadata": { "editable": true, "slideshow": { @@ -5391,58 +5512,92 @@ }, "outputs": [], "source": [ - "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", - "print(arc_update)\n", - "print(arc_update.upper())\n", - "print(arc_update.title())\n", - "print(arc_update.capitalize())" + "user_input = \" john.doe@email.com \"\n", + "email = user_input.strip()\n", + "print(f\"Original: '{user_input}'\")\n", + "print(f\"Cleaned: '{email}'\")" ] }, { "cell_type": "markdown", - "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", + "id": "2fd63835", "metadata": { "editable": true, "slideshow": { "slide_type": "slide" - }, - "tags": [] + } }, "source": [ - "## Removing white space" + "These methods work with any string and don't raise exceptions, but you may want to validate the results." ] }, { "cell_type": "code", "execution_count": null, - "id": "22763b5f-7576-43c5-a237-925dce9b88aa", + "id": "8f1ceba1", + "metadata": {}, + "outputs": [], + "source": [ + "# Transforming methods don't raise exceptions, but you can validate transformed results\n", + "def process_username(username):\n", + " \"\"\"Process and validate a username.\"\"\"\n", + " if not isinstance(username, str):\n", + " raise TypeError(f\"Username must be a string, got {type(username).__name__}\")\n", + " \n", + " # Transform: strip whitespace and convert to lowercase\n", + " processed = username.strip().lower()\n", + " \n", + " # Validate the result\n", + " if not processed:\n", + " raise ValueError(\"Username cannot be empty after processing\")\n", + " \n", + " if len(processed) < 3:\n", + " raise ValueError(f\"Username must be at least 3 characters, got {len(processed)}\")\n", + " \n", + " return processed\n", + "\n", + "# Valid case\n", + "try:\n", + " result = process_username(\" JohnDoe \")\n", + " print(f\"โœ“ Processed username: '{result}'\")\n", + "except ValueError as e:\n", + " print(f\"Error: {e}\")\n", + "\n", + "# Invalid case\n", + "try:\n", + " result = process_username(\" AB \")\n", + " print(f\"โœ“ Processed username: '{result}'\")\n", + "except ValueError as e:\n", + " print(f\"Error: {e}\")" + ] + }, + { + "cell_type": "markdown", + "id": "6cf8076f-8f50-49ae-b558-39336c323880", "metadata": { "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, "tags": [] }, - "outputs": [], "source": [ - "user_input = \" john.doe@email.com \"\n", - "email = user_input.strip()\n", - "print(f\"Original: '{user_input}'\")\n", - "print(f\"Cleaned: '{email}'\")" + "## Splitting/joining string methods" ] }, { "cell_type": "markdown", - "id": "6cf8076f-8f50-49ae-b558-39336c323880", + "id": "71a4546c", "metadata": { "editable": true, "slideshow": { - "slide_type": "slide" - }, - "tags": [] + "slide_type": "" + } }, "source": [ - "## Extracting/concatenating the individual words or parts" + "These methods allow you to break strings apart into lists of substrings, or combine lists of strings into a single string. They're particularly useful for parsing text data or formatting output:\n", + "* `split(separator)` - splits string into a list at each occurrence of separator (defaults to whitespace)\n", + "* `join(iterable)` - joins elements of an iterable into a single string with the string as separator" ] }, { @@ -5467,6 +5622,19 @@ "print(line.split('jumped'))" ] }, + { + "cell_type": "markdown", + "id": "b21113ff", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "**Note**: `split()` never raises an exception" + ] + }, { "cell_type": "markdown", "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", @@ -5478,7 +5646,7 @@ "tags": [] }, "source": [ - "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" + "The `join` operation is `a_string.join()` where `a_string` is placed between every string of a list" ] }, { @@ -5515,6 +5683,40 @@ "print(\"\\n\".join(line_list))" ] }, + { + "cell_type": "markdown", + "id": "0deaf239", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + } + }, + "source": [ + "`join()` will raise a `TypeError` if the iterable contains non-string elements" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "225bdd40", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "flags = [16384,1048576]\n", + "\n", + "for i in range(len(flags)):\n", + " flags_str = \"+\".join(flags[i])\n", + "#flags_str = \"+\".join(str(flag) for flag in flags)\n", + "#print(flags_str)" + ] + }, { "cell_type": "markdown", "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", @@ -6416,7 +6618,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.13.0" } }, "nbformat": 4, From f94a5956f19fbc4235e20e77e60bcf2c02f4d0a8 Mon Sep 17 00:00:00 2001 From: Dmitry Nikolaenko Date: Thu, 26 Feb 2026 18:44:55 +0000 Subject: [PATCH 4/9] Update Jupyterlite Github workflow --- .github/workflows/cleanup.yml | 12 +++++++ .github/workflows/deploy.yml | 68 ++++------------------------------- 2 files changed, 19 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/cleanup.yml diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml new file mode 100644 index 0000000..63470c7 --- /dev/null +++ b/.github/workflows/cleanup.yml @@ -0,0 +1,12 @@ +name: Cleanup Deleted Branch + +on: + delete + +permissions: + contents: write + +jobs: + cleanup: + uses: DurhamARC-Training/PythonCourse-jupyterlite/.github/workflows/cleanup-branch-deployment.yml@main + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 92a88c7..f8c2afe 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,67 +1,13 @@ -name: Deploy Jupyter Notebooks to GitHub Pages +name: Deploy JupyterLite on: push: - branches: [ main ] + branches: ['**'] # Deploy all branches -env: - TEMPLATE_REPO: 'DurhamARC-Training/PythonCourse-jupyterlite' -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout template repository - uses: actions/checkout@v4 - with: - repository: ${{ env.TEMPLATE_REPO }} - - - name: Checkout main repository into content directory - uses: actions/checkout@v4 - with: - path: content - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install template dependencies - run: | - python -m pip install -r requirements.txt - - - name: Install content dependencies - run: | - if [ -f content/requirements.txt ]; then - echo "Found content/requirements.txt, installing dependencies..." - python -m pip install -r content/requirements.txt - else - echo "No content/requirements.txt found, skipping content dependencies" - fi - - - name: Build the JupyterLite site - run: | - cp README.md content - jupyter lite build --contents content --output-dir dist - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: ./dist +permissions: + contents: write +jobs: deploy: - needs: build - if: github.ref == 'refs/heads/main' - permissions: - pages: write - id-token: write - - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - - runs-on: ubuntu-latest - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + uses: DurhamARC-Training/PythonCourse-jupyterlite/.github/workflows/deploy-jupyterlite.yml@main + secrets: inherit \ No newline at end of file From d3e14842a82c0a811f9b33cc5d501bede2f5af32 Mon Sep 17 00:00:00 2001 From: Niolon Date: Fri, 27 Feb 2026 11:13:09 +0000 Subject: [PATCH 5/9] update module section --- Intermediate.ipynb | 95 +++++++++++++++++++++---- Intermediate_full.ipynb | 152 +++++++++++++++++++++++++++------------- 2 files changed, 185 insertions(+), 62 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index 32e64a0..a0fab5a 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -4470,29 +4470,33 @@ }, { "cell_type": "markdown", - "id": "9e1c43a8", + "id": "dc4b7323-f4f7-4b51-b6da-f651abf5029e", "metadata": { "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "## Importing _modules_" + "Modules let us:\n", + "- Use code that others have already written and tested\n", + "- Load in only the functionality we need\n", + "- Know exactly where a piece of functionality comes from" ] }, { "cell_type": "markdown", - "id": "eed64626", + "id": "9e1c43a8", "metadata": { "editable": false, "slideshow": { - "slide_type": "" - } + "slide_type": "slide" + }, + "tags": [] }, "source": [ - "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." + "## Importing _modules_" ] }, { @@ -4502,7 +4506,8 @@ "editable": false, "slideshow": { "slide_type": "" - } + }, + "tags": [] }, "source": [ "There are several ways of importing _modules_:" @@ -4601,6 +4606,71 @@ "print(square_root(25))" ] }, + { + "cell_type": "markdown", + "id": "04bec6e4-8e4d-4899-a3c3-c9abd332f275", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "## Why Namespaces Matter\n", + "\n", + "The word `log` means two very different things:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4de72e4c-2795-4b4d-8542-10729a74f44a", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import logging\n", + "\n", + "math.log(100, 10) # A logarithm: 2.0\n", + "\n", + "logging.log(20, \"Hello\") # A logbook entry: records a message" + ] + }, + { + "cell_type": "markdown", + "id": "36f46ead-b9a1-481f-8798-edbfc58b5504", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Without namespaces, Python, and your reader, couldn't tell them apart." + ] + }, + { + "cell_type": "markdown", + "id": "fbf736e6-8dfb-4a00-86fb-5e71de650e9f", + "metadata": { + "editable": false, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "----\n", + "This is why importing a whole module into namespace is usually a bad idea:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -4614,10 +4684,9 @@ }, "outputs": [], "source": [ - "# import all functions, variables, and classes from a module into the global namespace\n", - "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", + "# import all functions, variables, and classes from a module - better to avoid this\n", "from math import *\n", - "print(int(sqrt(4.0)))" + "print(sqrt(4.0))" ] }, { @@ -4626,12 +4695,12 @@ "metadata": { "editable": false, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, "tags": [] }, "source": [ - "---\n", + "## Getting help\n", "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." ] }, diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 03331a1..f411e01 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -4875,29 +4875,33 @@ }, { "cell_type": "markdown", - "id": "9e1c43a8", + "id": "dc4b7323-f4f7-4b51-b6da-f651abf5029e", "metadata": { "editable": true, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, "source": [ - "## Importing _modules_" + "Modules let us:\n", + "- Use code that others have already written and tested\n", + "- Load in only the functionality we need\n", + "- Know exactly where a piece of functionality comes from" ] }, { "cell_type": "markdown", - "id": "eed64626", + "id": "9e1c43a8", "metadata": { "editable": true, "slideshow": { - "slide_type": "" - } + "slide_type": "slide" + }, + "tags": [] }, "source": [ - "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." + "## Importing _modules_" ] }, { @@ -4907,7 +4911,8 @@ "editable": true, "slideshow": { "slide_type": "" - } + }, + "tags": [] }, "source": [ "There are several ways of importing _modules_:" @@ -5006,6 +5011,86 @@ "print(square_root(25))" ] }, + { + "cell_type": "markdown", + "id": "04bec6e4-8e4d-4899-a3c3-c9abd332f275", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "slide" + }, + "tags": [] + }, + "source": [ + "## Why Namespaces Matter\n", + "\n", + "The word `log` means two very different things:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4de72e4c-2795-4b4d-8542-10729a74f44a", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import logging\n", + "\n", + "math.log(100, 10) # A logarithm: 2.0\n", + "\n", + "logging.log(20, \"Hello\") # A logbook entry: records a message" + ] + }, + { + "cell_type": "markdown", + "id": "36f46ead-b9a1-481f-8798-edbfc58b5504", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Without namespaces, Python, and your reader, couldn't tell them apart." + ] + }, + { + "cell_type": "markdown", + "id": "ccbef34a-9226-4735-859d-378640ee9cc7", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "notes" + }, + "tags": [] + }, + "source": [ + "Notes:\n", + "- In JupyterLite, logging output is suppressed by default unless you explicitly configure a handler." + ] + }, + { + "cell_type": "markdown", + "id": "fbf736e6-8dfb-4a00-86fb-5e71de650e9f", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "fragment" + }, + "tags": [] + }, + "source": [ + "----\n", + "This is why importing a whole module into namespace is usually a bad idea:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -5019,10 +5104,9 @@ }, "outputs": [], "source": [ - "# import all functions, variables, and classes from a module into the global namespace\n", - "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", + "# import all functions, variables, and classes from a module - better to avoid this\n", "from math import *\n", - "print(int(sqrt(4.0)))" + "print(sqrt(4.0))" ] }, { @@ -5031,12 +5115,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, "tags": [] }, "source": [ - "---\n", + "## Getting help\n", "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." ] }, @@ -5904,7 +5988,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "b10a1b92", "metadata": { "editable": true, @@ -5913,15 +5997,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Created example.csv with x and cos(x) values\n" - ] - } - ], + "outputs": [], "source": [ "import csv, math\n", "\n", @@ -5958,7 +6034,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", "metadata": { "editable": true, @@ -5967,20 +6043,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "First few lines of the file:\n", - "x_axis,y_axis\n", - "0.0,1.0\n", - "0.1,0.9950041652780258\n", - "0.2,0.9800665778412416\n", - "0.30000000000000004,0.955336489125606\n" - ] - } - ], + "outputs": [], "source": [ "# Show the first few lines to demonstrate what we created\n", "print(\"First few lines of the file:\")\n", @@ -5991,7 +6054,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "9af8c87f-62db-4a04-86d8-d51428395210", "metadata": { "editable": true, @@ -6000,16 +6063,7 @@ }, "tags": [] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The value of Y for X==1.0 saved in the file:\n", - "0.5403023058681398\n" - ] - } - ], + "outputs": [], "source": [ "# Show the value of Y for X==1.0 saved in the file\n", "print(\"The value of Y for X==1.0 saved in the file:\")\n", From 067ec18dbdb26f61851c4fefe3d4c69f453098a8 Mon Sep 17 00:00:00 2001 From: NADEN Date: Fri, 27 Feb 2026 14:05:25 +0000 Subject: [PATCH 6/9] Generated student file. --- Intermediate.ipynb | 2393 +++++++++++++++++++++----------------------- 1 file changed, 1120 insertions(+), 1273 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index b83adf6..f3207bb 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -4,11 +4,11 @@ "cell_type": "markdown", "id": "872c6494", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "ARC course \"Coding with Python\" (Intermediate level)\n", @@ -20,10 +20,10 @@ "cell_type": "markdown", "id": "2cd478b7", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "Welcome to our ARC course \"Coding with Python\" (Intermediate level).\n", @@ -47,11 +47,11 @@ "cell_type": "markdown", "id": "4d58fde4", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# The Python Environment\n", @@ -72,11 +72,11 @@ "cell_type": "markdown", "id": "e673e2cd", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# Table of Contents" @@ -86,11 +86,11 @@ "cell_type": "markdown", "id": "85069fdb", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ " - [0. Introduction](#0.-Introduction)\n", @@ -100,26 +100,26 @@ "- [Part I](#Part-I)\n", " - [1. Recap](#1.-Recap)\n", " - [2. Data structures](#2.-Data-structures)\n", - " - [3. Conditional expression](#3.-Conditional-expressions)\n", + " - [3. Conditional expressions](#3.-Conditional-expressions)\n", " - [4. Comprehensions](#4.-Comprehensions)\n", - " - [5. Exceptions](#5-exceptions)\n", + " - [5. Exceptions](#5.-Exceptions)\n", "\n", "- [Part II](#Part-II)\n", - " - [5. Brief introduction to Object-Oriented Programming](#6-brief-introduction-to-object-oriented-programming)\n", - " - [6. Introduction to modules](#7-introduction-to-modules)\n", - " - [7. Advanced string manipulation](#8-advanced-string-manipulation)\n", - " - [8. (Optional) Working with modules: Examples and creating your own](#9-optional-working-with-modules-examples-and-creating-your-own)\n" + " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", + " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", + " - [8. (Optional) Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", + " - [9. (Optional) Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] }, { "cell_type": "markdown", "id": "153ed362", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# 0. Introduction" @@ -129,11 +129,11 @@ "cell_type": "markdown", "id": "6ba842c0", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Course objectives" @@ -143,11 +143,11 @@ "cell_type": "markdown", "id": "b1d20fc9", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "By the end of this course, you should know:\n", @@ -164,11 +164,11 @@ "cell_type": "markdown", "id": "cdfa9441", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Useful resources" @@ -178,10 +178,10 @@ "cell_type": "markdown", "id": "3eadf8e2", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "There are plenty of resources to learn Python in the Internet from. These can be recommended by this tutorial for further learning:\n", @@ -196,11 +196,11 @@ "cell_type": "markdown", "id": "26d2d446", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# **Part I**" @@ -210,11 +210,11 @@ "cell_type": "markdown", "id": "4e49802b", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# **1.** Recap" @@ -224,10 +224,10 @@ "cell_type": "markdown", "id": "f99bdeea", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "This section is a brief recap of materials covered in the Beginner Python course:\n", @@ -245,11 +245,11 @@ "cell_type": "markdown", "id": "b721c83a", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Data Types, variables, operators" @@ -268,11 +268,11 @@ } } }, - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Variables\n", @@ -286,7 +286,6 @@ "execution_count": null, "id": "decd8f2c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -302,7 +301,6 @@ "execution_count": null, "id": "1489fa3d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -318,7 +316,6 @@ "execution_count": null, "id": "fb6110d3", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -333,7 +330,6 @@ "execution_count": null, "id": "ac31e498", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -347,11 +343,11 @@ "cell_type": "markdown", "id": "e1bd297e", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -365,7 +361,6 @@ "execution_count": null, "id": "94b6e716", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -381,7 +376,6 @@ "execution_count": null, "id": "d11dd969", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -396,11 +390,11 @@ "cell_type": "markdown", "id": "2a63c2dd", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Data types" @@ -410,11 +404,11 @@ "cell_type": "markdown", "id": "7ab44bf2", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "As with any programming language, Python can deal with many different data types. Among the basic ones are `str` strings, `int` integers, `float` floating-point numbers and `bool` booleans.\n", @@ -428,11 +422,11 @@ "cell_type": "markdown", "id": "c33c20f5", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "#### Numerical" @@ -442,11 +436,11 @@ "cell_type": "markdown", "id": "7a797eab", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "##### Floating-point representation:\n", @@ -462,7 +456,6 @@ "execution_count": null, "id": "c13d9a15", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -478,7 +471,6 @@ "execution_count": null, "id": "26b8760c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -492,10 +484,10 @@ "cell_type": "markdown", "id": "b9324c88", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "_NOTE_: Scientific notation is supported!" @@ -506,7 +498,6 @@ "execution_count": null, "id": "3253e3d0", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -523,10 +514,10 @@ "cell_type": "markdown", "id": "397f9f86", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "##### Integer representation:\n", @@ -539,7 +530,6 @@ "execution_count": null, "id": "3342a922", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -555,7 +545,6 @@ "execution_count": null, "id": "36e671e1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -569,10 +558,10 @@ "cell_type": "markdown", "id": "b68a5bbf", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "**Numerical Operators** \n", @@ -593,7 +582,6 @@ "execution_count": null, "id": "af62e441", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -608,7 +596,6 @@ "execution_count": null, "id": "7e7ef933", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -623,7 +610,6 @@ "execution_count": null, "id": "28810d42", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -638,7 +624,6 @@ "execution_count": null, "id": "8b66a0a4", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -653,7 +638,6 @@ "execution_count": null, "id": "6984dbe1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -668,7 +652,6 @@ "execution_count": null, "id": "74e37711", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -682,11 +665,11 @@ "cell_type": "markdown", "id": "a5e3ab30", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "#### String" @@ -696,10 +679,10 @@ "cell_type": "markdown", "id": "ba570bf4", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "A string is a series of characters enclosed in quotes, either single or double, used to represent text." @@ -710,7 +693,6 @@ "execution_count": null, "id": "ea3df5a1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -728,7 +710,6 @@ "execution_count": null, "id": "e3c09d2d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -743,11 +724,11 @@ "cell_type": "markdown", "id": "50a4347d", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**String Concatenation** \n", @@ -760,7 +741,6 @@ "execution_count": null, "id": "d9fadfdc", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -776,11 +756,11 @@ "cell_type": "markdown", "id": "d20cb9b3", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Comments" @@ -790,11 +770,11 @@ "cell_type": "markdown", "id": "7ac031a7", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Used to write notes or comments about code, as well as description of what the code is doing, or the variables used." @@ -805,7 +785,6 @@ "execution_count": null, "id": "41b7cdfe", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -823,7 +802,6 @@ "execution_count": null, "id": "9c50f102", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -842,7 +820,6 @@ "execution_count": null, "id": "3f72dedf", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -860,11 +837,11 @@ "cell_type": "markdown", "id": "8ee98ee9", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## User Input" @@ -874,11 +851,11 @@ "cell_type": "markdown", "id": "6b2e3c6e", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "You can use `input()` to read user input: " @@ -889,7 +866,6 @@ "execution_count": null, "id": "a1178a62", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -906,11 +882,11 @@ "cell_type": "markdown", "id": "52819c95", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Reading and Writing Files" @@ -920,11 +896,11 @@ "cell_type": "markdown", "id": "a0966820", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Opening a File**\n", @@ -945,7 +921,6 @@ "execution_count": null, "id": "38966db9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -963,11 +938,11 @@ "cell_type": "markdown", "id": "aadba414", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Reading from a File**\n", @@ -983,7 +958,6 @@ "execution_count": null, "id": "7f0a6056", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1000,7 +974,6 @@ "execution_count": null, "id": "ec567746", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1016,11 +989,11 @@ "cell_type": "markdown", "id": "1f1185e6", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Writing to a File**" @@ -1030,11 +1003,11 @@ "cell_type": "markdown", "id": "179f132a", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "One way we can write to files is using the `write()` function." @@ -1044,11 +1017,11 @@ "cell_type": "markdown", "id": "e998f8fe", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Using the `with` keyword:" @@ -1059,7 +1032,6 @@ "execution_count": null, "id": "911d44b3", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1076,11 +1048,11 @@ "cell_type": "markdown", "id": "b61a8691", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Lists" @@ -1090,11 +1062,11 @@ "cell_type": "markdown", "id": "9c82edee", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Python can work not only with basic data types mentioned before, but also with compound ones. Compound data types in Python are a powerful tool for organizing and storing data. Among the most commonly used is _lists_ which we learned about in the beginner's course.\n", @@ -1108,11 +1080,11 @@ "cell_type": "markdown", "id": "8bb91a15", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "An ordered list of items, accessed by a numerical index (starting at `0`). Elements within a list can be removed, modified, or accessed by their index, and a list can have values added to it.\n", @@ -1125,7 +1097,6 @@ "execution_count": null, "id": "fdc8600e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1141,11 +1112,11 @@ "cell_type": "markdown", "id": "efc747a1", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**List Access** \n", @@ -1157,7 +1128,6 @@ "execution_count": null, "id": "2b2c4dee", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1172,7 +1142,6 @@ "execution_count": null, "id": "3f87d56b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1187,7 +1156,6 @@ "execution_count": null, "id": "b686d58d", "metadata": { - "editable": true, "slideshow": { "slide_type": "fragment" }, @@ -1203,7 +1171,6 @@ "execution_count": null, "id": "1f916c68", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1217,11 +1184,11 @@ "cell_type": "markdown", "id": "b8369a1a", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Slicing** \n", @@ -1233,7 +1200,6 @@ "execution_count": null, "id": "e0fac9bf", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1249,7 +1215,6 @@ "execution_count": null, "id": "586edf14", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1264,7 +1229,6 @@ "execution_count": null, "id": "9f0dea38", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1279,7 +1243,6 @@ "execution_count": null, "id": "bab8e8a0", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1293,11 +1256,11 @@ "cell_type": "markdown", "id": "fe6ffaf2", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Empty List** \n", @@ -1309,7 +1272,6 @@ "execution_count": null, "id": "0edf3fa6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1324,11 +1286,11 @@ "cell_type": "markdown", "id": "f87cfa0f", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Repetitions and Conditions\n", @@ -1340,10 +1302,10 @@ "cell_type": "markdown", "id": "9ca15865", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "#### Boolean" @@ -1354,7 +1316,6 @@ "execution_count": null, "id": "d7b7abb8", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1371,7 +1332,6 @@ "execution_count": null, "id": "9296bb88", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1385,11 +1345,11 @@ "cell_type": "markdown", "id": "eae67d96", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Logical Operators** \n", @@ -1400,11 +1360,11 @@ "cell_type": "markdown", "id": "b38b2739", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**AND:**" @@ -1415,7 +1375,6 @@ "execution_count": null, "id": "db33e773", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1447,11 +1406,11 @@ "cell_type": "markdown", "id": "8b00b658", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -1463,7 +1422,6 @@ "execution_count": null, "id": "725d0173", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1494,10 +1452,10 @@ "cell_type": "markdown", "id": "6a10fe2f", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "---\n", @@ -1509,7 +1467,6 @@ "execution_count": null, "id": "27378611", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1538,10 +1495,10 @@ "cell_type": "markdown", "id": "9303b3ff", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "**Conditions** \n", @@ -1566,7 +1523,6 @@ "execution_count": null, "id": "a0af6ea1", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1595,11 +1551,11 @@ "cell_type": "markdown", "id": "3246bbe1", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Else/Elif** \n", @@ -1612,7 +1568,6 @@ "execution_count": null, "id": "8cab77e6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1634,11 +1589,11 @@ "cell_type": "markdown", "id": "8c87d3f8", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Repetitions** \n", @@ -1649,11 +1604,11 @@ "cell_type": "markdown", "id": "095edef4", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "For Each Loop: \n", @@ -1665,7 +1620,6 @@ "execution_count": null, "id": "c7dc2e03", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1683,10 +1637,10 @@ "cell_type": "markdown", "id": "76e99a09", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "The above describes `for each animal in animal_list`." @@ -1696,11 +1650,11 @@ "cell_type": "markdown", "id": "e5b05a2c", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -1712,7 +1666,6 @@ "execution_count": null, "id": "b14f546d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1729,7 +1682,6 @@ "execution_count": null, "id": "713884f6", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1745,7 +1697,6 @@ "execution_count": null, "id": "b3078796", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1760,11 +1711,11 @@ "cell_type": "markdown", "id": "99b52e73", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "While Loop \n", @@ -1778,7 +1729,6 @@ "execution_count": null, "id": "136268d9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -1796,10 +1746,10 @@ "cell_type": "markdown", "id": "89cd06cc", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "_NOTE_: The `break` keyword can be used to stop execution of a loop. \n", @@ -1810,10 +1760,10 @@ "cell_type": "markdown", "id": "b6c7b631", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "## Functions" @@ -1823,11 +1773,11 @@ "cell_type": "markdown", "id": "ad3766a1", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "A function is a reusable block of code used to perform a specific task.\n", @@ -1841,11 +1791,11 @@ "cell_type": "markdown", "id": "b83eb9fd", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Parameters/Arguments** \n", @@ -1856,11 +1806,11 @@ "cell_type": "markdown", "id": "25dddacf", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "**Returns** \n", @@ -1871,11 +1821,11 @@ "cell_type": "markdown", "id": "aa2983d4", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Here is a very basic example of a function:" @@ -1886,7 +1836,6 @@ "execution_count": null, "id": "d4ca99fa", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1906,11 +1855,11 @@ "cell_type": "markdown", "id": "429c78c2", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Note that we are able to save the result of `sum_numbers`, to a variable which we have aptly named `calculated_value`, which can be reused later." @@ -1920,11 +1869,11 @@ "cell_type": "markdown", "id": "f64d31aa", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -1936,7 +1885,6 @@ "execution_count": null, "id": "643f4038", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -1959,10 +1907,10 @@ "cell_type": "markdown", "id": "b07b62ef", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "Without specifying the `name` argument, the `generate_greeting` will use the default value specified within the function definition." @@ -1972,11 +1920,11 @@ "cell_type": "markdown", "id": "7e95592e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# 2. Data structures\n", @@ -1989,11 +1937,11 @@ "cell_type": "markdown", "id": "aae1eed3", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## List methods\n", @@ -2005,7 +1953,6 @@ "execution_count": null, "id": "cb25df04", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2021,10 +1968,10 @@ "cell_type": "markdown", "id": "50327676", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "We can access the number of elements with `len`" @@ -2035,7 +1982,6 @@ "execution_count": null, "id": "250138ea", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2050,11 +1996,11 @@ "cell_type": "markdown", "id": "5bda75d6", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Adding and removing values\n", @@ -2066,7 +2012,6 @@ "execution_count": null, "id": "e1027891", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2082,7 +2027,6 @@ "execution_count": null, "id": "48a12e4a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2097,10 +2041,10 @@ "cell_type": "markdown", "id": "7e4b1b25", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "removing a specific element" @@ -2111,7 +2055,6 @@ "execution_count": null, "id": "3a23bbd1", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2126,11 +2069,11 @@ "cell_type": "markdown", "id": "290722a8", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Iterating over lists\n", @@ -2142,7 +2085,6 @@ "execution_count": null, "id": "54db3f5f", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2157,10 +2099,10 @@ "cell_type": "markdown", "id": "81d1f392", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "we can iterate over the list starting from the back using `reversed`" @@ -2171,7 +2113,6 @@ "execution_count": null, "id": "230fdc57", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2187,10 +2128,10 @@ "cell_type": "markdown", "id": "f6fce9a1", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "and `sorted`, sorts the values" @@ -2201,7 +2142,6 @@ "execution_count": null, "id": "100c9390", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2217,10 +2157,10 @@ "cell_type": "markdown", "id": "b26074d7", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "If you want a reversed new list you need to convert the iterator into a list" @@ -2231,7 +2171,6 @@ "execution_count": null, "id": "5279a6b8", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2247,7 +2186,6 @@ "execution_count": null, "id": "ad34c0bf", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2263,11 +2201,11 @@ "cell_type": "markdown", "id": "e00e5f84", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Checking if an item is in a list\n", @@ -2280,7 +2218,6 @@ "execution_count": null, "id": "0e61b0ef", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2295,11 +2232,11 @@ "cell_type": "markdown", "id": "8be77c84", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Emptying a list" @@ -2310,7 +2247,6 @@ "execution_count": null, "id": "867aa292", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2325,11 +2261,11 @@ "cell_type": "markdown", "id": "04d87890", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## _Tuples_\n", @@ -2341,7 +2277,6 @@ "execution_count": null, "id": "3afd38d5", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2357,7 +2292,6 @@ "execution_count": null, "id": "4bf75e76", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2375,7 +2309,6 @@ "execution_count": null, "id": "4775ecb7", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "fragment" @@ -2399,7 +2332,6 @@ "execution_count": null, "id": "8f3c40be", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2415,11 +2347,11 @@ "cell_type": "markdown", "id": "812d5a14", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "The dictionary method `items` returns a list of tuples (see an exercise after _dictionaries_)." @@ -2429,11 +2361,11 @@ "cell_type": "markdown", "id": "66b0bb86", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## _Sets_\n", @@ -2445,7 +2377,6 @@ "execution_count": null, "id": "a9622e5a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2462,7 +2393,6 @@ "execution_count": null, "id": "95e68a89", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2479,7 +2409,6 @@ "execution_count": null, "id": "d84ee17a", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2495,11 +2424,11 @@ "cell_type": "markdown", "id": "4131293a", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "There are a few operators that work with sets as well as some useful methods:\n", @@ -2524,11 +2453,11 @@ "cell_type": "markdown", "id": "03763f24", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### _Example 1_\n", @@ -2540,7 +2469,6 @@ "execution_count": null, "id": "18bac89c", "metadata": { - "editable": true, "remove_code": "after:# Generate new list with unique values", "slideshow": { "slide_type": "" @@ -2558,10 +2486,10 @@ "cell_type": "markdown", "id": "d0501b3f", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "### _Example 2_\n", @@ -2574,7 +2502,6 @@ "execution_count": null, "id": "a924df94", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -2594,11 +2521,11 @@ "cell_type": "markdown", "id": "245d1725", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## _Dictionaries_\n", @@ -2609,11 +2536,11 @@ "cell_type": "markdown", "id": "8b83afd4", "metadata": { - "editable": false, "slideshow": { "slide_type": null }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "- _Dictionaries_ are like labelled drawers:\n", @@ -2631,7 +2558,6 @@ "execution_count": null, "id": "200a2eba", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -2648,7 +2574,6 @@ "execution_count": null, "id": "553707eb", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2664,7 +2589,6 @@ "execution_count": null, "id": "eb9476c1", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2681,7 +2605,6 @@ "execution_count": null, "id": "112e1c7b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2698,7 +2621,6 @@ "execution_count": null, "id": "9affafb3", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2714,11 +2636,11 @@ "cell_type": "markdown", "id": "de3b6a25-6150-4fb7-8cab-e97872f8974e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Accessing values from dictionaries" @@ -2739,7 +2661,6 @@ "execution_count": null, "id": "a71f9c99-e59e-4470-aa19-fde963cbb276", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2766,7 +2687,6 @@ "execution_count": null, "id": "3a6e30f1-c169-4ecb-9d59-f0e7cef1fb56", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2782,11 +2702,11 @@ "cell_type": "markdown", "id": "968a105e-1cc1-45e7-aa30-d19ce18943fe", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### Looping over a dictionary" @@ -2807,7 +2727,6 @@ "execution_count": null, "id": "6081d62b-efd5-4b51-ba91-7307e53c9a36", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2824,7 +2743,6 @@ "execution_count": null, "id": "b65b03ae-768e-4bee-8502-b0ea4d633e5c", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2841,7 +2759,6 @@ "execution_count": null, "id": "2ff80eea-453f-44ac-8ddf-5f084008127b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2857,11 +2774,11 @@ "cell_type": "markdown", "id": "f73a79d3", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Notes on _lists_, _strings_, _tuples_, _sets_, and _dictionaries_" @@ -2871,11 +2788,11 @@ "cell_type": "markdown", "id": "624091b9", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "* **_Lists_** and **_dictionaries_** are _mutable_, which means their contents can be changed.\n", @@ -2887,11 +2804,11 @@ "cell_type": "markdown", "id": "7271e95a", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Similarities of _lists_ and _strings_:\n", @@ -2905,7 +2822,6 @@ "execution_count": null, "id": "502cadb7", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2924,7 +2840,6 @@ "execution_count": null, "id": "3f76fba0", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -2942,11 +2857,11 @@ "cell_type": "markdown", "id": "b35c5868", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -2959,7 +2874,6 @@ "execution_count": null, "id": "662c5a6c", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -2982,11 +2896,11 @@ "cell_type": "markdown", "id": "70429b28", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## _Lists_ and _strings_ behave differently when we try to make copies." @@ -2997,7 +2911,6 @@ "execution_count": null, "id": "ceb379c2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3016,7 +2929,6 @@ "execution_count": null, "id": "d7738594", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3034,11 +2946,11 @@ "cell_type": "markdown", "id": "36c080f0", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "Everything in Python is an object. This includes numbers, strings, and lists and any other data structure. When we\n", @@ -3052,7 +2964,6 @@ "execution_count": null, "id": "e4dfb2cb", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3070,11 +2981,11 @@ "cell_type": "markdown", "id": "b424a761", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Have a Play!" @@ -3084,10 +2995,10 @@ "cell_type": "markdown", "id": "38cc0279", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "### _Exercise 1 (dictionaries)_" @@ -3097,11 +3008,11 @@ "cell_type": "markdown", "id": "3f494a2e", "metadata": { - "editable": false, "lines_to_next_cell": 2, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "1) Create a dictionary of the days in the months of the year.\n", @@ -3113,7 +3024,6 @@ "execution_count": null, "id": "3ae9acd3", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3134,11 +3044,11 @@ "cell_type": "markdown", "id": "1178f7dc", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### _Exercise 2 (dictionaries)_" @@ -3148,11 +3058,11 @@ "cell_type": "markdown", "id": "31e0b17b", "metadata": { - "editable": false, "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "1. Create a dictionary of several countries and capitals. Think about what's going to be a key and a value.\n", @@ -3166,7 +3076,6 @@ "execution_count": null, "id": "d3e579d3", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3187,11 +3096,11 @@ "cell_type": "markdown", "id": "07d53abe", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### _Exercise 3 (tuples)_" @@ -3201,10 +3110,10 @@ "cell_type": "markdown", "id": "6e83da5f", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "Try `items()` method on the dictionary you've created before. Print that out. What kind of data structure does it return?" @@ -3215,7 +3124,6 @@ "execution_count": null, "id": "fb62cca7", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3236,11 +3144,11 @@ "cell_type": "markdown", "id": "f2ad81c8", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### _Exercise 4 (lists)_" @@ -3250,10 +3158,10 @@ "cell_type": "markdown", "id": "7c84ec76", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "Given this list: " @@ -3264,7 +3172,6 @@ "execution_count": null, "id": "f964f97b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3279,10 +3186,10 @@ "cell_type": "markdown", "id": "01378c1c", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "Complete these tasks:" @@ -3293,7 +3200,6 @@ "execution_count": null, "id": "9ad284dd", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3317,11 +3223,11 @@ "cell_type": "markdown", "id": "5bc9a961", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# 3. Conditional expressions\n", @@ -3333,7 +3239,6 @@ "execution_count": null, "id": "56986833", "metadata": { - "editable": true, "remove_code": "after:# shorten by ternary expression", "slideshow": { "slide_type": "fragment" @@ -3357,11 +3262,11 @@ "cell_type": "markdown", "id": "21217bab", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -3373,7 +3278,6 @@ "execution_count": null, "id": "81768bf7", "metadata": { - "editable": true, "remove_code": "# catch None with or", "slideshow": { "slide_type": "" @@ -3393,11 +3297,11 @@ "cell_type": "markdown", "id": "63274497", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "---\n", @@ -3409,7 +3313,6 @@ "execution_count": null, "id": "40fb97c5", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3429,7 +3332,6 @@ "execution_count": null, "id": "23e5335e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -3444,11 +3346,11 @@ "cell_type": "markdown", "id": "a6f9d70c-8116-4e65-b719-e3eb2afa7338", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Have a play!" @@ -3458,10 +3360,10 @@ "cell_type": "markdown", "id": "6dd1230b", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "#### Conditional Expression\n", @@ -3473,7 +3375,6 @@ "execution_count": null, "id": "30eb5d01", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3492,11 +3393,11 @@ "cell_type": "markdown", "id": "f77b3d5e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# 4. Comprehensions" @@ -3506,10 +3407,10 @@ "cell_type": "markdown", "id": "0002904e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" - } + }, + "editable": false }, "source": [ "### `list` comprehensions\n", @@ -3521,7 +3422,6 @@ "execution_count": null, "id": "d2d4f618", "metadata": { - "editable": true, "slideshow": { "slide_type": "" } @@ -3538,10 +3438,10 @@ "cell_type": "markdown", "id": "2b2a108f", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "You can simplify it using list comprehensions:" @@ -3552,7 +3452,6 @@ "execution_count": null, "id": "8e6b943b", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3568,10 +3467,10 @@ "cell_type": "markdown", "id": "fba1d4bd", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "editable": false }, "source": [ "We can create a list for only a subset with a condition:" @@ -3582,7 +3481,6 @@ "execution_count": null, "id": "7fa7800c", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3609,7 +3507,6 @@ "execution_count": null, "id": "ef3ac491-86bf-4e69-9c32-1e320773202d", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3625,11 +3522,11 @@ "cell_type": "markdown", "id": "23631ac8", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### `dict` comprehensions" @@ -3640,7 +3537,6 @@ "execution_count": null, "id": "b19190dc", "metadata": { - "editable": true, "remove_code": "after:# print a dictionaries of lengths for the names", "slideshow": { "slide_type": "" @@ -3658,11 +3554,11 @@ "cell_type": "markdown", "id": "2d4e0235", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "### `set` comprehensions" @@ -3673,7 +3569,6 @@ "execution_count": null, "id": "27175fde", "metadata": { - "editable": true, "remove_code": "non-comments", "slideshow": { "slide_type": "" @@ -3689,11 +3584,11 @@ "cell_type": "markdown", "id": "f8beaad4", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Have a play!\n", @@ -3709,7 +3604,6 @@ "execution_count": null, "id": "72ee6d83", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "non-comments", "slideshow": { @@ -3727,11 +3621,11 @@ "cell_type": "markdown", "id": "2092afdb", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "#### Dictionary Comprehension\n", @@ -3743,7 +3637,6 @@ "execution_count": null, "id": "9dc013da", "metadata": { - "editable": true, "lines_to_next_cell": 0, "remove_code": "after:# your solution", "slideshow": { @@ -3761,11 +3654,11 @@ "cell_type": "markdown", "id": "6e54d68e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# 5. Exceptions\n", @@ -3787,11 +3680,11 @@ "cell_type": "markdown", "id": "e4ffd520", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Exceptions often are used for known edge cases \n" @@ -3819,11 +3712,11 @@ "cell_type": "markdown", "id": "d26956f3", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Reraising Meaningful exceptions" @@ -3834,7 +3727,6 @@ "execution_count": null, "id": "6a7114a0", "metadata": { - "editable": true, "remove_code": "after:# Modify function to list the index and content of the entry that caused the error", "slideshow": { "slide_type": "" @@ -3864,11 +3756,11 @@ "cell_type": "markdown", "id": "44d08a7e", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Raising exceptions for invalid values" @@ -3899,11 +3791,11 @@ "cell_type": "markdown", "id": "6011ded7", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## The `finally` block will always be executed, either after code execution or after the failure\n", @@ -3925,7 +3817,6 @@ "execution_count": null, "id": "6401f075", "metadata": { - "editable": true, "remove_code": "after:# Modify function to always include the timing", "slideshow": { "slide_type": "" @@ -3963,11 +3854,11 @@ "cell_type": "markdown", "id": "bbc81d0f", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Best Practice:\n", @@ -3986,11 +3877,11 @@ "cell_type": "markdown", "id": "67e040dc", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "## Have a play:" @@ -4000,11 +3891,11 @@ "cell_type": "markdown", "id": "ff630616", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "\n", @@ -4043,11 +3934,11 @@ "cell_type": "markdown", "id": "930a9ea5", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# **Part II**" @@ -4055,103 +3946,83 @@ }, { "cell_type": "markdown", - "id": "9e01e73d", + "id": "ecad0562", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "# 6. Brief introduction to Object-Oriented Programming" + "# 6. Introduction to modules\n", + "A _module_ is a single file (or collection of files) that is intended to be imported and used in other Python programs. It can include functions, classes, variables, and runnable code." ] }, { "cell_type": "markdown", - "id": "3627c2ef", + "id": "9e1c43a8", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "* Python is an object oriented programming language. Object-Oriented Programming (OOP) is a programming paradigm based on the concept of \"objects\" which can contain:\n", - " - Data (attributes)\n", - " - Code (methods)" + "## Importing _modules_" ] }, { "cell_type": "markdown", - "id": "8393fae9", + "id": "eed64626", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "editable": false }, "source": [ - "\n", - "## 1. Classes and Objects\n", - " - Class: A blueprint for creating objects (Think a cookiecutter)\n", - " - Object: An instance of a class (The created cookies)\n", - "\n", - "\n", - "A simple example:" + "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "5005c5bc", + "cell_type": "markdown", + "id": "db90a278", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, - "tags": [] + "editable": false }, - "outputs": [], "source": [ - "# Simple example\n", - "class CourseParticipant:\n", - " def __init__(self, name, email):\n", - " self.name = name\n", - " self.email = email\n", - "\n", - " def welcome(self):\n", - " print(f\"Welcome {self.name}! We're glad to have you.\")\n", - "\n", - "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", - "participant1.welcome()" + "There are several ways of importing _modules_:" ] }, { - "cell_type": "markdown", - "id": "b2a91e2a", + "cell_type": "code", + "execution_count": null, + "id": "0f8ee4bb", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## 2. Encapsulation\n", - " - Bundling data and methods that work on that data within one unit\n", - " - Restricting access to certain details\n", - " - Is also often used to keep track of states." + "# import the whole module\n", + "import math\n", + "\n", + "# module's function name is in the module's namespace\n", + "print(math.sqrt(16.0))" ] }, { "cell_type": "code", "execution_count": null, - "id": "74cd0847", + "id": "338eca3f", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4159,49 +4030,32 @@ }, "outputs": [], "source": [ - "class CourseParticipant:\n", - " def __init__(self, name, email):\n", - " self.name = name\n", - " self.email = email\n", - " self.registered_attendance = False\n", - "\n", - " def welcome(self):\n", - " print(f\"Welcome {self.name}! We're glad to have you.\")\n", - "\n", - " def register_attendance(self):\n", - " self.registered_attendance = True\n", - " print(f\"{self.name} has been registered for attendance.\")\n", - "\n", - "# use the class\n", - "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", - "participant1.welcome()\n", - "participant1.register_attendance()\n" + "# import several modules at once\n", + "import pathlib, sys, time" ] }, { - "cell_type": "markdown", - "id": "df442469", + "cell_type": "code", + "execution_count": null, + "id": "2f29773e", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## 3. Inheritance\n", - " - Creating new classes that extend the functionality of existing classes\n", - " - We _inherit_ the properties of the base class `CourseParticipant`\n", - " - `super()` lets us invoke the function of the same name from the base class\n", - " - Carefully decide between inheritance and composition (see soon)" + "# use 'as' keyword to change the name of the module\n", + "import math as m\n", + "print(m.sqrt(36.0))" ] }, { "cell_type": "code", "execution_count": null, - "id": "8e94ff6d", + "id": "77b96e95", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4209,45 +4063,35 @@ }, "outputs": [], "source": [ - "class ExternalParticipant(CourseParticipant):\n", - " def __init__(self, name, email, company):\n", - " super().__init__(name, email)\n", - " self.company = company\n", - "\n", - " def contact_company(self):\n", - " print(f\"Contacting {self.company} regarding course participation.\")\n", + "# import only a selected function from a module\n", + "from math import sqrt\n", "\n", - "external_participant1 = ExternalParticipant(\"Bob\", \"bob@example.com\", \"Cooperative Inc.\")\n", - "external_participant1.welcome()\n", - "external_participant1.contact_company()\n" + "# the function's name is in the global namespace\n", + "print(sqrt(49))" ] }, { - "cell_type": "markdown", - "id": "2cf3958b", + "cell_type": "code", + "execution_count": null, + "id": "ce4f29f0", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## 4. Polymorphism\n", - "- Definition: Call the same method name on different object types and get type-specific behavior.\n", - "- Key idea: Write code to an interface, not a concrete class.\n", - "- Why it matters:\n", - " - Decouples caller from concrete types (extensible)\n", - " - Removes conditionals/type-checks (cleaner)\n", - " - Eases testing and substitution (mocks/fakes)" + "# change the name of the function in the module\n", + "from math import sqrt as square_root\n", + "print(square_root(25))" ] }, { "cell_type": "code", "execution_count": null, - "id": "a414bc89", + "id": "44c18b00", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4255,238 +4099,123 @@ }, "outputs": [], "source": [ - "class DurhamUniversityParticipant(CourseParticipant):\n", - " def register_attendance(self):\n", - " super().register_attendance()\n", - " print(f\" Also registered attendance with the internal additional system for {self.name}\")\n", - " \n", - "\n", - "participants = [\n", - " ExternalParticipant(\"Alice\", \"alice@example.com\", \"Acme Corp\"),\n", - " DurhamUniversityParticipant(\"Bob\", \"bob@durham.ac.uk\"),\n", - " CourseParticipant(\"Charlie\", \"charlie@example.com\")\n", - "]\n", - "\n", - "for participant in participants:\n", - " participant.register_attendance()" + "# import all functions, variables, and classes from a module into the global namespace\n", + "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", + "from math import *\n", + "print(int(sqrt(4.0)))" ] }, { "cell_type": "markdown", - "id": "fdb800a8", + "id": "d1cc0855", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## 5. Composition\n", - "\n", - "- Definition: Build classes by combining other objects (a class has collaborators).\n", - "- Why choose it:\n", - " - Favors flexibility and reuse over tight inheritance ties\n", - " - Swap components easily\n", - "\n", - "- If your `__init__` functions have alternative optional parameters, this is often a sign you should use composition\n", - "- Especially favour composition if there are several options for different behaviours that can be combined interchangeably (_has-a_ vs interitance: _is-a_)\n" + "---\n", + "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." ] }, { "cell_type": "code", "execution_count": null, - "id": "2cea837b", + "id": "558e0d9e", "metadata": { - "editable": true, "slideshow": { "slide_type": "" - }, - "tags": [] + } }, "outputs": [], "source": [ - "class Messenger:\n", - " def send_message(self, message):\n", - " pass\n", - "\n", - "class EmailMessenger(Messenger):\n", - "\n", - " def __init__(self, email):\n", - " self.email = email\n", - "\n", - " def send_message(self, message):\n", - " print(f\"Sending email to {self.email}: {message}\")\n", - "\n", - "class TeamsMessenger(Messenger):\n", - "\n", - " def __init__(self, user_id):\n", - " self.user_id = user_id\n", - "\n", - " def send_message(self, message):\n", - " print(f\"Sending Teams message to {self.user_id}: {message}\")\n", - "\n", - "\n", - "class Participant:\n", - " def __init__(self, name, messenger):\n", - " self.name = name\n", - " self.messenger = messenger\n", - "\n", - " def welcome(self):\n", - " self.messenger.send_message(f\"Welcome {self.name}!\")\n", - "\n", - "# Use the Participant class\n", - "participants = [\n", - " Participant(\"Alice\", EmailMessenger(\"alice@example.com\")),\n", - " Participant(\"Bob\", TeamsMessenger(\"bob123\"))\n", - "]\n", - "\n", - "for participant in participants:\n", - " participant.welcome()\n" + "# get a list of the functions and variables in the module\n", + "dir(math)" ] }, { - "cell_type": "markdown", - "id": "129df112", + "cell_type": "code", + "execution_count": null, + "id": "01d2c703", "metadata": { - "editable": false + "slideshow": { + "slide_type": "" + } }, + "outputs": [], "source": [ - "---" + "# get a long description\n", + "help(math)" ] }, { "cell_type": "markdown", - "id": "d9c8cd20", + "id": "8e33b8e3", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, - "tags": [] - }, - "source": [ - "## Have a play!" - ] - }, - { - "cell_type": "markdown", - "id": "28e31e47", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "" - }, - "tags": [] + "editable": false }, "source": [ - "### Plant Sensor API Exercise\n", - "You've been given a virtual sensor API module which you can import with (`import sensor_api`) that can monitor plants. \n", - "The API provides three functions:\n", - "\n", - "- `connect(sensor_id)`: Connects to a sensor (returns True/False)\n", - "- `disconnect(sensor_id)`: Disconnects from a sensor (returns True/False) \n", - "- `send_message(message)`: Sends a command and receives a reading (returns float or None)\n", - "\n", - "#### Message Format\n", - "Messages must be formatted as: `\"SENSOR_ID:COMMAND\"`\n", - "\n", - "Available commands:\n", - "- `SOIL_HUMIDITY`: Get soil humidity (0-100%)\n", - "- `AIR_HUMIDITY`: Get air humidity (0-100%)\n", - "- `TEMPERATURE`: Get temperature in Celsius\n", - "\n", - "#### Before\n", - "This is how working with the API would currently look:\n", - "\n", - "```python\n", - "import sensor_api\n", - "\n", - "sensor_id = \"GREENHOUSE_01\"\n", - "sensor_api.connect(sensor_id)\n", - "\n", - "soil_humidity = float(sensor_api.send_message(f\"{id}:SOIL_HUMIDITY\"))\n", - "air_humidity = float(sensor_api.send_message(f\"{id}:AIR_HUMIDITY\"))\n", - "temperature = float(sensor_api.send_message(f\"{id}:TEMPERATURE\"))\n", - "\n", - "print(f\"\\n=== Plant Sensor {sensor_id} Readings ===\")\n", - "print(f\"Soil Humidity: {soil_humidity}%\")\n", - "print(f\"Air Humidity: {air_humidity}%\")\n", - "print(f\"Temperature: {temperature}\u00b0C\")\n", - "print(\"=\" * 35)\n", - "sensor_api.disconnect(id)\n", - "```\n", - "\n", - "#### Your Task\n", - "Create a `PlantSensor` class that:\n", - "\n", - "1. Stores the sensor ID when created\n", - "2. Automatically connects when initialized\n", - "3. Provides easy-to-use methods for each measurement type\n", - "4. Properly disconnects when done\n", - "5. Displays all readings in a nice format\n", - "\n", - "\n", - "\n", - "#### Desired result\n", - "```python\n", - "# This is how your class should work:\n", - "sensor = PlantSensor(\"PLANT_01\")\n", - "soil = sensor.get_soil_humidity()\n", - "air = sensor.get_air_humidity()\n", - "temp = sensor.get_temperature()\n", - "sensor.display_readings()\n", - "sensor.disconnect()\n", - "```" + "---" ] }, { "cell_type": "markdown", - "id": "9cb57fee", + "id": "2d186e61-b776-483a-a6b9-0890af512e80", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "### Implementation" + "# 7. Advanced string manipulation" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "fb0d76f6", + "cell_type": "markdown", + "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", "metadata": { - "editable": true, - "remove_code": "all", "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "\n" + "* Adjusting case\n", + "* Formatting strings\n", + " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", + "* Quering the existence, replacing, splitting" ] }, { "cell_type": "markdown", - "id": "1624a7a4", + "id": "00e14678-81a2-4509-815a-53f9f2fdb332", "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [], "editable": false }, "source": [ - "You can use this to try to use your class. You can comment out functionality, if you have not implemented it yet" + "## Finding values \n", + "* `find()` and `index()` both return index of a substring,\n", + " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", + " - `find()` returns `-1` when a values was not found\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "49d66487", + "id": "0eab0a2d-eea9-4c33-b700-56eb293ef28b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4494,81 +4223,77 @@ }, "outputs": [], "source": [ - "my_plant = PlantSensor(\"GREENHOUSE_01\")\n", - "\n", - "# Take readings\n", - "my_plant.get_soil_humidity()\n", - "my_plant.get_air_humidity()\n", - "my_plant.get_temperature()\n", - "\n", - "# Display results\n", - "my_plant.display_readings()\n", - "\n", - "# Clean up\n", - "my_plant.disconnect()" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "print(line.find('fox'))\n", + "print(line.index('fox'))" ] }, { - "cell_type": "markdown", - "id": "ecad0562", + "cell_type": "code", + "execution_count": null, + "id": "134c6eba-8897-4ee8-a6e5-f3740a0a4d21", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "# 7. Introduction to modules\n", - "A _module_ is a single file (or collection of files) that is intended to be imported and used in other Python programs. It can include functions, classes, variables, and runnable code." + "print(line.find('wombat'))" ] }, { - "cell_type": "markdown", - "id": "9e1c43a8", + "cell_type": "code", + "execution_count": null, + "id": "fc5a28ef-8a31-434a-a653-1662cc274945", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Importing _modules_" + "try:\n", + " print(line.index('wombat'))\n", + "except ValueError:\n", + " print(\"A wombat isn't mentioned in the text\")" ] }, { "cell_type": "markdown", - "id": "eed64626", + "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" - } + "slide_type": "slide" + }, + "tags": [], + "editable": false }, "source": [ - "Python comes with hundreds of _modules_ doing all sorts of things. Also, many 3rd-party modules are available to download from the Internet." + "## Checking conditions on strings" ] }, { "cell_type": "markdown", - "id": "db90a278", + "id": "7b5ac28b-5cfb-4c43-bf54-093c240cbe2b", "metadata": { - "editable": false, "slideshow": { "slide_type": "" - } + }, + "tags": [], + "editable": false }, "source": [ - "There are several ways of importing _modules_:" + "* Checking whether a string starts or ends a certain way is really common and easy" ] }, { "cell_type": "code", "execution_count": null, - "id": "0f8ee4bb", + "id": "77d4d329-9e07-4100-a84e-bd8e55287b5d", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4576,19 +4301,18 @@ }, "outputs": [], "source": [ - "# import the whole module\n", - "import math\n", + "line = \"the quick brown fox jumped over a lazy dog\"\n", "\n", - "# module's function name is in the module's namespace\n", - "print(math.sqrt(16.0))" + "print(line.startswith('the')) # True\n", + "print(line.endswith('dog')) # True - makes sense!\n", + "print(line.endswith('fox')) # False - now it's clear why" ] }, { "cell_type": "code", "execution_count": null, - "id": "338eca3f", + "id": "7e401e7c-4cc2-4de7-8e11-45654b9592b9", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4596,34 +4320,30 @@ }, "outputs": [], "source": [ - "# import several modules at once\n", - "import pathlib, sys, time" + "# Case sensitivity matters\n", + "print(line.startswith('The')) # False - capital T\n", + "print(line.startswith('the')) # True - lowercase t" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "2f29773e", + "cell_type": "markdown", + "id": "e040bf97-a6bd-493e-b047-2041b5a99131", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# use 'as' keyword to change the name of the module\n", - "import math as m\n", - "print(m.sqrt(36.0))" + "* The canonical way to search a string (if not interested in the index):" ] }, { "cell_type": "code", "execution_count": null, - "id": "77b96e95", + "id": "47c2d357", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4631,37 +4351,29 @@ }, "outputs": [], "source": [ - "# import only a selected function from a module\n", - "from math import sqrt\n", - "\n", - "# the function's name is in the global namespace\n", - "print(sqrt(49))" + "if \"fox\" in line:\n", + " print(\"A fox has been seen\")" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "ce4f29f0", + "cell_type": "markdown", + "id": "fe3ce02d-08bd-4c52-a935-d27b843dde39", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# change the name of the function in the module\n", - "from math import sqrt as square_root\n", - "print(square_root(25))" + "## Replacing a value:" ] }, { "cell_type": "code", "execution_count": null, - "id": "44c18b00", + "id": "292d8b56-1142-4927-9320-9c6331f5a962", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4669,126 +4381,130 @@ }, "outputs": [], "source": [ - "# import all functions, variables, and classes from a module into the global namespace\n", - "# - better to avoid this as some names from the module can interfere with your own variable names in the global namespace\n", - "from math import *\n", - "print(int(sqrt(4.0)))" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "print(line)\n", + "print(line.replace('brown', 'red'))" ] }, { "cell_type": "markdown", - "id": "d1cc0855", + "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", "metadata": { - "editable": false, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "---\n", - "To get help on a module at the Python shell, import it the whole (the very first way), then you can..." + "## Bring all words to a common case" ] }, { "cell_type": "code", "execution_count": null, - "id": "558e0d9e", + "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", "metadata": { - "editable": true, "slideshow": { "slide_type": "" - } + }, + "tags": [] }, "outputs": [], "source": [ - "# get a list of the functions and variables in the module\n", - "dir(math)" + "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", + "print(arc_update)\n", + "print(arc_update.upper())\n", + "print(arc_update.title())\n", + "print(arc_update.capitalize())" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "01d2c703", + "cell_type": "markdown", + "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" - } + "slide_type": "slide" + }, + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# get a long description\n", - "help(math)" + "## Removing white space" ] }, { - "cell_type": "markdown", - "id": "8e33b8e3", + "cell_type": "code", + "execution_count": null, + "id": "22763b5f-7576-43c5-a237-925dce9b88aa", "metadata": { - "editable": false, "slideshow": { - "slide_type": "fragment" - } + "slide_type": "" + }, + "tags": [] }, + "outputs": [], "source": [ - "---" + "user_input = \" john.doe@email.com \"\n", + "email = user_input.strip()\n", + "print(f\"Original: '{user_input}'\")\n", + "print(f\"Cleaned: '{email}'\")" ] }, { "cell_type": "markdown", - "id": "2d186e61-b776-483a-a6b9-0890af512e80", + "id": "6cf8076f-8f50-49ae-b558-39336c323880", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "# 8. Advanced string manipulation" + "## Extracting/concatenating the individual words or parts" ] }, { - "cell_type": "markdown", - "id": "c9016a2e-dee1-4030-a1a0-8e519a84be6f", + "cell_type": "code", + "execution_count": null, + "id": "1f26c482", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "* Adjusting case\n", - "* Formatting strings\n", - " - _Note_: Modification requires assignment, because these functions return a copy, not modifying the original string\n", - "* Quering the existence, replacing, splitting" + "line = \"the quick brown fox jumped over a lazy dog\"\n", + "\n", + "# split by space\n", + "print(line.split())\n", + "\n", + "# split by word\n", + "print(line.split('jumped'))" ] }, { "cell_type": "markdown", - "id": "00e14678-81a2-4509-815a-53f9f2fdb332", + "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Finding values \n", - "* `find()` and `index()` both return index of a substring,\n", - " - `index()` raises a `ValueError` exception when not found (_exception handling_)\n", - " - `find()` returns `-1` when a values was not found\n" + "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" ] }, { "cell_type": "code", "execution_count": null, - "id": "0eab0a2d-eea9-4c33-b700-56eb293ef28b", + "id": "5c81a93d-6fca-40e5-ae22-6697a9352272", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4796,17 +4512,15 @@ }, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "print(line.find('fox'))\n", - "print(line.index('fox'))" + "string_list = [\"A\", \"list\", \"of\", \"split\", \"words\"]\n", + "print(\" \".join(string_list))" ] }, { "cell_type": "code", "execution_count": null, - "id": "134c6eba-8897-4ee8-a6e5-f3740a0a4d21", + "id": "cb9837fc-dd67-447c-b503-8029678581ab", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4814,62 +4528,125 @@ }, "outputs": [], "source": [ - "print(line.find('wombat'))" + "line_list = [\"First line\", \"Second line\"]\n", + "print(\"\\n\".join(line_list))" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "fc5a28ef-8a31-434a-a653-1662cc274945", + "cell_type": "markdown", + "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "try:\n", - " print(line.index('wombat'))\n", - "except ValueError:\n", - " print(\"A wombat isn't mentioned in the text\")" + "## Have a play!" ] }, { "cell_type": "markdown", - "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", + "id": "a2cd1c9a-967b-4f4b-8153-c4f55d50b377", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Checking conditions on strings" + "### Practical Example: Text Processing Pipeline\n", + "\n", + "Let's combine several string manipulation techniques to clean and process some messy user data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3639015f-81e0-4abf-a574-0b2f1d08181b", + "metadata": {}, + "outputs": [], + "source": [ + "# Raw user input with various issues\n", + "user_data = [\n", + " \" john.doe@email.com \",\n", + " \"JANE SMITH \",\n", + " \" Bob_Wilson@test.co.uk \",\n", + " \"invalid-email-format\",\n", + " \" Sarah.Connor@future.net \"\n", + "]\n", + "\n", + "print(\"=== Text Processing Pipeline ===\")\n", + "print(\"Original data:\")\n", + "for i, item in enumerate(user_data, 1):\n", + " print(f\"{i}. '{item}'\")\n", + "\n", + "print(\"\\nProcessed data:\")\n", + "valid_emails = []\n", + "\n", + "for i, entry in enumerate(user_data, 1):\n", + " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", + " # Step 1: Remove whitespace\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 1 command)\n", + " \n", + " print(f\" After strip(): '{cleaned}'\")\n", + " \n", + " # Step 2: Handle different formats\n", + " if \"<\" in cleaned and \">\" in cleaned:\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 1 command)\n", + " \n", + " print(f\" Extracted from brackets: '{email_part}'\")\n", + " else:\n", + " email_part = cleaned\n", + " print(f\" No brackets found, using as-is\")\n", + " \n", + " # Basic email validation\n", + " if \"@\" in email_part and \".\" in email_part:\n", + " # Step 3: Normalize to lowercase\n", + " # TODO: WRITE YOUR SOLUTION HERE\n", + " #... (hint: 2 commands)\n", + "\n", + " print(f\" \u2713 Valid email: {normalized}\")\n", + " else:\n", + " print(f\" \u2717 Invalid: {email_part}\")\n", + "\n", + "print(f\"\\n=== Results ===\")\n", + "print(f\"Found {len(valid_emails)} valid emails:\")\n", + "for email in valid_emails:\n", + " print(f\" - {email}\")\n", + "\n", + "# Bonus: Extract unique domains\n", + "# TODO: WRITE YOUR SOLUTION HERE\n", + "#... (hint: use for loop as we have a list of emails)\n", + "\n", + "print(f\"\\nUnique domains found: {sorted(domains)}\")" ] }, { "cell_type": "markdown", - "id": "7b5ac28b-5cfb-4c43-bf54-093c240cbe2b", + "id": "9fb3a479-cddd-4b00-8e5d-88194c82f9ed", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "* Checking whether a string starts or ends a certain way is really common and easy" + "#### Solution" ] }, { "cell_type": "code", "execution_count": null, - "id": "77d4d329-9e07-4100-a84e-bd8e55287b5d", + "id": "d69d4356-f129-40c7-a682-2f2f5fb9d190", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -4877,114 +4654,115 @@ }, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "\n", - "print(line.startswith('the')) # True\n", - "print(line.endswith('dog')) # True - makes sense!\n", - "print(line.endswith('fox')) # False - now it's clear why" + "\n" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7e401e7c-4cc2-4de7-8e11-45654b9592b9", + "cell_type": "markdown", + "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# Case sensitivity matters\n", - "print(line.startswith('The')) # False - capital T\n", - "print(line.startswith('the')) # True - lowercase t" + "# 8. (Optional) Working with modules: Examples and creating your own" ] }, { "cell_type": "markdown", - "id": "e040bf97-a6bd-493e-b047-2041b5a99131", + "id": "b14a6818", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "* The canonical way to search a string (if not interested in the index):" + "## Some useful _modules_" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "47c2d357", + "cell_type": "markdown", + "id": "012efab2", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "if \"fox\" in line:\n", - " print(\"A fox has been seen\")" + "Python comes with a program called _pip_ (Python Package Installer) which will automatically fetch packages released and listed on PyPI: `pip install `" ] }, { "cell_type": "markdown", - "id": "fe3ce02d-08bd-4c52-a935-d27b843dde39", + "id": "eb000d98", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Replacing a value:" + "| Name | Description |\n", + "|------------------|-------------|\n", + "| **`time`** | functions for dealing with time\n", + "| **`datetime`** | allows to work with dates and times together\n", + "| **`os`** | functions for working with files, directories and operating system (lowlevel)\n", + "| **`pathlib`** | Classes for working with paths, files and directories in a higher level implementation\n", + "| **`shutils`** | contains a function to copy files\n", + "| **`sys`** | contains a function to quit your program\n", + "| **`zipfile`** | allows to compress/extract files or directory of files into/from a zip file\n", + "| **`urllib`** | allows to get files from the internet\n", + "| **`math`** | math functions such as `sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `floor`, `ceil` |\n", + "| **`numpy`** | fundamental package for scientific computing (a multidimensional array object; routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting; basic linear algebra, basic statistical operations, random simulation and much more) |\n", + "| **`scipy`** | a collection of mathematical algorithms and convenience functions built on the NumPy extension (high-level commands and classes for the manipulation and visualization of data) |\n", + "| **`matplotlib`** | library for plotting\n", + "| **`sympy`** | symbolic computations\n", + "| **`itertools`** | provides a generator-like object named `permutations`\n", + "| **`csv`** | parsing and writing `csv` files" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "292d8b56-1142-4927-9320-9c6331f5a962", + "cell_type": "markdown", + "id": "4e16a864", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "print(line)\n", - "print(line.replace('brown', 'red'))" + "## Using _modules_" ] }, { "cell_type": "markdown", - "id": "bb4faee5-8c3f-4919-acbe-1b7b2cf7b700", + "id": "17798548", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Bring all words to a common case" + "### _Example_\n", + "Interfacing with the files: **`pathlib`**" ] }, { "cell_type": "code", "execution_count": null, - "id": "a95784ad-44fc-4e7c-9b16-caa09fedbc60", + "id": "cf38baf4-5486-4c17-bc93-42510f8a6db7", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -4992,246 +4770,216 @@ }, "outputs": [], "source": [ - "arc_update = \"ThE HAmILton suPERcompUTER is beiNg UPGraded\"\n", - "print(arc_update)\n", - "print(arc_update.upper())\n", - "print(arc_update.title())\n", - "print(arc_update.capitalize())" + "from pathlib import Path\n", + "# Create a Path object for the current directory\n", + "current_directory = Path('.')" ] }, { - "cell_type": "markdown", - "id": "7a25cc7f-6040-4c03-ac38-b5f9a7baef41", + "cell_type": "code", + "execution_count": null, + "id": "47affbe3-0eb6-4ed6-8717-3ef05b072a80", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "fragment" }, "tags": [] }, + "outputs": [], "source": [ - "## Removing white space" + "# list all ipynb files in the current directory\n", + "for file in current_directory.glob('*.ipynb'):\n", + " print(file.name)" ] }, { "cell_type": "code", "execution_count": null, - "id": "22763b5f-7576-43c5-a237-925dce9b88aa", + "id": "98714766-5033-43d8-a9a3-0589b7bf32ec", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "user_input = \" john.doe@email.com \"\n", - "email = user_input.strip()\n", - "print(f\"Original: '{user_input}'\")\n", - "print(f\"Cleaned: '{email}'\")" - ] - }, - { - "cell_type": "markdown", - "id": "6cf8076f-8f50-49ae-b558-39336c323880", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "## Extracting/concatenating the individual words or parts" + "# We can also list all files in the current directory\n", + "for file in current_directory.iterdir():\n", + " print(file.name)" ] }, { "cell_type": "code", "execution_count": null, - "id": "1f26c482", + "id": "3fe290ad-e12f-4021-b8ef-a6d9bd6a7467", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "line = \"the quick brown fox jumped over a lazy dog\"\n", - "\n", - "# split by space\n", - "print(line.split())\n", + "# go to subfolders and files in these folders using /\n", + "file_path = current_directory / 'data' / 'data_file.txt'\n", "\n", - "# split by word\n", - "print(line.split('jumped'))" + "# check whether a file exists\n", + "if file_path.exists():\n", + " print(f\"The file {file_path} exists.\")" ] }, { - "cell_type": "markdown", - "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", + "cell_type": "code", + "execution_count": null, + "id": "cdcbc0b1-197d-4fc5-95e9-9501868b7525", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, + "outputs": [], "source": [ - "The operation in the other direction is `a_string.join()` where `a_string` is placed between every string of a list" + "# Create a new test folder\n", + "new_folder = current_directory / 'test_folder'\n", + "new_folder.mkdir(exist_ok=True) # exist_ok=True prevents error if folder already exists" ] }, { "cell_type": "code", "execution_count": null, - "id": "5c81a93d-6fca-40e5-ae22-6697a9352272", + "id": "b33c4e26-ec82-405d-97a5-bd88488c06d8", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "string_list = [\"A\", \"list\", \"of\", \"split\", \"words\"]\n", - "print(\" \".join(string_list))" + "# Write text to a file in test_folder\n", + "output = \"This is some output\\nSecond line!\"\n", + "output_file = new_folder / 'output.txt'\n", + "output_file.write_text(output)" ] }, { "cell_type": "code", "execution_count": null, - "id": "cb9837fc-dd67-447c-b503-8029678581ab", + "id": "89847e34-7e99-4b89-904f-b7ec2c8dd774", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, "tags": [] }, "outputs": [], "source": [ - "line_list = [\"First line\", \"Second line\"]\n", - "print(\"\\n\".join(line_list))" + "# Read back the content from the file we just created\n", + "content = output_file.read_text() # Read from the same file we created\n", + "print(\"Content of the file we just created:\")\n", + "print(content)" ] }, { "cell_type": "markdown", - "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", + "id": "4e9801e0", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Have a play!" + "---\n", + "We'll demonstrate how to use modules in the actual code using the example of reading/writing files. In the _Beginner_ course, we showed the basic reading/writing files using the built-in functions of Python. But there's a better way of doing that by means of the specialised module called **`csv`**." ] }, { "cell_type": "markdown", - "id": "a2cd1c9a-967b-4f4b-8153-c4f55d50b377", + "id": "a306f3cb", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "### Practical Example: Text Processing Pipeline\n", - "\n", - "Let's combine several string manipulation techniques to clean and process some messy user data" + "Writing a csv file:" ] }, { "cell_type": "code", "execution_count": null, - "id": "3639015f-81e0-4abf-a574-0b2f1d08181b", - "metadata": {}, + "id": "b10a1b92", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ - "# Raw user input with various issues\n", - "user_data = [\n", - " \" john.doe@email.com \",\n", - " \"JANE SMITH \",\n", - " \" Bob_Wilson@test.co.uk \",\n", - " \"invalid-email-format\",\n", - " \" Sarah.Connor@future.net \"\n", - "]\n", - "\n", - "print(\"=== Text Processing Pipeline ===\")\n", - "print(\"Original data:\")\n", - "for i, item in enumerate(user_data, 1):\n", - " print(f\"{i}. '{item}'\")\n", - "\n", - "print(\"\\nProcessed data:\")\n", - "valid_emails = []\n", - "\n", - "for i, entry in enumerate(user_data, 1):\n", - " print(f\"\\nProcessing entry {i}: '{entry}'\")\n", - " # Step 1: Remove whitespace\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 1 command)\n", - " \n", - " print(f\" After strip(): '{cleaned}'\")\n", - " \n", - " # Step 2: Handle different formats\n", - " if \"<\" in cleaned and \">\" in cleaned:\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 1 command)\n", - " \n", - " print(f\" Extracted from brackets: '{email_part}'\")\n", - " else:\n", - " email_part = cleaned\n", - " print(f\" No brackets found, using as-is\")\n", - " \n", - " # Basic email validation\n", - " if \"@\" in email_part and \".\" in email_part:\n", - " # Step 3: Normalize to lowercase\n", - " # TODO: WRITE YOUR SOLUTION HERE\n", - " #... (hint: 2 commands)\n", - "\n", - " print(f\" \u2713 Valid email: {normalized}\")\n", - " else:\n", - " print(f\" \u2717 Invalid: {email_part}\")\n", - "\n", - "print(f\"\\n=== Results ===\")\n", - "print(f\"Found {len(valid_emails)} valid emails:\")\n", - "for email in valid_emails:\n", - " print(f\" - {email}\")\n", + "import csv, math\n", "\n", - "# Bonus: Extract unique domains\n", - "# TODO: WRITE YOUR SOLUTION HERE\n", - "#... (hint: use for loop as we have a list of emails)\n", + "# Read the file object\n", + "with open(\"example.csv\", 'w') as out_f:\n", + " # use csv.writer to interact\n", + " writer = csv.writer(out_f, delimiter=',')\n", + " # write the headings\n", + " writer.writerow([\"x_axis\", \"y_axis\"])\n", + " # generate the data for x\n", + " x_axis = [x * 0.1 for x in range(0, 100)]\n", + " # write x and cos(x) for every entry\n", + " for x in x_axis:\n", + " writer.writerow([x, math.cos(x)])\n", "\n", - "print(f\"\\nUnique domains found: {sorted(domains)}\")" + "print(\"Created example.csv with x and cos(x) values\")" ] }, { "cell_type": "markdown", - "id": "9fb3a479-cddd-4b00-8e5d-88194c82f9ed", + "id": "3a9c7b35", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "slideshow": { + "slide_type": "slide" + }, + "tags": [], + "editable": false + }, + "source": [ + "---\n", + "Now, let\u2019s extract the value for `y_axis` when `x_axis` is `1.0` for the csv we just wrote:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", "metadata": { - "editable": false, "slideshow": { "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "#### Solution" + "# Show the first few lines to demonstrate what we created\n", + "print(\"First few lines of the file:\")\n", + "with open(\"example.csv\", 'r') as f:\n", + " for _ in range(5):\n", + " print(f.readline().strip())" ] }, { "cell_type": "code", "execution_count": null, - "id": "d69d4356-f129-40c7-a682-2f2f5fb9d190", + "id": "9af8c87f-62db-4a04-86d8-d51428395210", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -5239,276 +4987,350 @@ }, "outputs": [], "source": [ - "\n" + "# Show the value of Y for X==1.0 saved in the file\n", + "print(\"The value of Y for X==1.0 saved in the file:\")\n", + "with open (\"example.csv\", 'r') as in_f:\n", + " reader = csv.reader(in_f, delimiter=',')\n", + " next(reader) # skip header\n", + " for row in reader:\n", + " if row[0] == \"1.0\":\n", + " print(row[1])\n", + " break" ] }, { "cell_type": "markdown", - "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", + "id": "6ee8121a", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "# 9. (Optional) Working with modules: Examples and creating your own" + "---" ] }, { "cell_type": "markdown", - "id": "b14a6818", + "id": "a00f019b", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Some useful _modules_" + "## Building your own module\n", + "\n", + " - If you have a .py file in a path that is available to python, you can import any object defined in that file.\n", + " - If you have `mymodule.py` in your folder you can just write:\n", + "\n", + " `import mymodule`\n", + "\n", + " and use a function defined in there with `mymodule.my_function(arg)`\n", + " - of course you can also use the method\n", + "\n", + " `from mymodule import my_function`" ] }, { "cell_type": "markdown", - "id": "012efab2", + "id": "dd9284d3-b9cc-43b1-a369-731c3e09351e", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "Python comes with a program called _pip_ (Python Package Installer) which will automatically fetch packages released and listed on PyPI: `pip install `" + "### Simple example:" ] }, { "cell_type": "markdown", - "id": "eb000d98", + "id": "9bdac1cc-4bdc-4a40-b4d7-25e24edc611f", "metadata": { - "editable": false, - "slideshow": { - "slide_type": "" - }, - "tags": [] + "editable": false }, "source": [ - "| Name | Description |\n", - "|------------------|-------------|\n", - "| **`time`** | functions for dealing with time\n", - "| **`datetime`** | allows to work with dates and times together\n", - "| **`os`** | functions for working with files, directories and operating system (lowlevel)\n", - "| **`pathlib`** | Classes for working with paths, files and directories in a higher level implementation\n", - "| **`shutils`** | contains a function to copy files\n", - "| **`sys`** | contains a function to quit your program\n", - "| **`zipfile`** | allows to compress/extract files or directory of files into/from a zip file\n", - "| **`urllib`** | allows to get files from the internet\n", - "| **`math`** | math functions such as `sin`, `cos`, `tan`, `exp`, `log`, `sqrt`, `floor`, `ceil` |\n", - "| **`numpy`** | fundamental package for scientific computing (a multidimensional array object; routines for fast operations on arrays, including mathematical, logical, shape manipulation, sorting, selecting; basic linear algebra, basic statistical operations, random simulation and much more) |\n", - "| **`scipy`** | a collection of mathematical algorithms and convenience functions built on the NumPy extension (high-level commands and classes for the manipulation and visualization of data) |\n", - "| **`matplotlib`** | library for plotting\n", - "| **`sympy`** | symbolic computations\n", - "| **`itertools`** | provides a generator-like object named `permutations`\n", - "| **`csv`** | parsing and writing `csv` files" + "Create a file called `calculator.py`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d4973db-7dbb-4a57-a027-d12de35c9d48", + "metadata": {}, + "outputs": [], + "source": [ + "module_path = 'calculator.py'\n", + "\n", + "module_content = \\\n", + "\"\"\"def add(a, b):\n", + " return a + b\n", + "\n", + "def multiply(a, b):\n", + " return a * b\n", + "\n", + "PI = 3.14159\n", + "\"\"\"\n", + "\n", + "with open(module_path, 'w') as fobj:\n", + " fobj.write(module_content)" ] }, { "cell_type": "markdown", - "id": "4e16a864", + "id": "a547c272-803a-46e8-af1f-00600ad11e92", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" + }, + "tags": [], + "editable": false + }, + "source": [ + "Then you can use it in your main program:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d3584bd-f99b-4fc8-9b19-db321634f329", + "metadata": { + "slideshow": { + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Using _modules_" + "import calculator\n", + "\n", + "result = calculator.add(5, 3)\n", + "print(f\"5 + 3 = {result}\")\n", + "print(f\"Pi is approximately {calculator.PI}\")" ] }, { "cell_type": "markdown", - "id": "17798548", + "id": "47dd6a0c", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "### _Example_\n", - "Interfacing with the files: **`pathlib`**" + "### ```__main__``` special built-in variable\n", + "**Important:** When creating modules, you need to be careful about code that runs automatically. So, python files can be executed with `python mymodule.py` or loaded from with `import`.\n", + "However, all commands just put into a python file will be executed on import.\n", + "\n", + "The answer is to introduce a `__main__` block that is only executed when the file is called as a script.\n", + "It is good practice to have all code executed in a script to be either in a function or in this block." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "cf38baf4-5486-4c17-bc93-42510f8a6db7", + "cell_type": "markdown", + "id": "7f4123ae", "metadata": { - "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "fragment" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "from pathlib import Path\n", - "# Create a Path object for the current directory\n", - "current_directory = Path('.')" + "\n", + "### Example content of `mymodule.py`:\n", + "```python\n", + "def myfunction():\n", + " print(\"I will be only printed when the function is called\")\n", + "\n", + "print(\"I will be called on import and execution as a script\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " print(\"I will only executed when called as a script\")\n", + "```" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "47affbe3-0eb6-4ed6-8717-3ef05b072a80", + "cell_type": "markdown", + "id": "bbe2196d", "metadata": { - "editable": true, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# list all ipynb files in the current directory\n", - "for file in current_directory.glob('*.ipynb'):\n", - " print(file.name)" + "## Have a play!\n", + "\n", + "**Exercise: Create and use your own module**\n", + "\n", + "1. **Create the module file**: Put the example content from the previous slide into a `mymodule.py` file in your folder\n", + "2. **Import and test**: Import `myfunction` into this notebook and run it\n", + "3. **Observe the output**: Notice what gets printed when you import the module\n", + "4. **Add functionality**: Create a new function that returns the sine of a value\n", + " - *Note: You might need to restart the kernel (Kernel \u2192 Restart Kernel) if you've already imported the module*\n", + "5. **Test your addition**: Import the updated module and test your sine function\n", + "\n", + "**Goal**: Understand how modules work, what code runs on import, and how to add your own functions." ] }, { "cell_type": "code", "execution_count": null, - "id": "98714766-5033-43d8-a9a3-0589b7bf32ec", + "id": "be842bd3", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# We can also list all files in the current directory\n", - "for file in current_directory.iterdir():\n", - " print(file.name)" + "# solution hint, cell 1\n", + "# (In the solution writing to a module is done as code in this cell)\n", + "# Write the content into the module file:\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "3fe290ad-e12f-4021-b8ef-a6d9bd6a7467", + "id": "506cd6b2", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# go to subfolders and files in these folders using /\n", - "file_path = current_directory / 'data' / 'data_file.txt'\n", - "\n", - "# check whether a file exists\n", - "if file_path.exists():\n", - " print(f\"The file {file_path} exists.\")" + "# solution hint, cell 2\n", + "# Import the module:\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "cdcbc0b1-197d-4fc5-95e9-9501868b7525", + "id": "454b088a", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# Create a new test folder\n", - "new_folder = current_directory / 'test_folder'\n", - "new_folder.mkdir(exist_ok=True) # exist_ok=True prevents error if folder already exists" + "# solution hint, cell 3\n", + "# Call the function from the module:\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "b33c4e26-ec82-405d-97a5-bd88488c06d8", + "id": "faee9ea4", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# Write text to a file in test_folder\n", - "output = \"This is some output\\nSecond line!\"\n", - "output_file = new_folder / 'output.txt'\n", - "output_file.write_text(output)" + "# solution hint, cell 4\n", + "# (In the solution writing to a module is done as code in this cell)\n", + "# To avoid the kernel restart, we output into a second file:\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "89847e34-7e99-4b89-904f-b7ec2c8dd774", + "id": "c8b612fa", "metadata": { - "editable": true, + "lines_to_next_cell": 0, + "remove_code": "non-comments", "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, "tags": [] }, "outputs": [], "source": [ - "# Read back the content from the file we just created\n", - "content = output_file.read_text() # Read from the same file we created\n", - "print(\"Content of the file we just created:\")\n", - "print(content)" + "# solution hint, cell 4\n", + "# Import your module and run the sine function from your own module:\n" ] }, { "cell_type": "markdown", - "id": "4e9801e0", + "id": "9e01e73d", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "---\n", - "We'll demonstrate how to use modules in the actual code using the example of reading/writing files. In the _Beginner_ course, we showed the basic reading/writing files using the built-in functions of Python. But there's a better way of doing that by means of the specialised module called **`csv`**." + "# 9. (Optional) Brief introduction to Object-Oriented Programming" ] }, { "cell_type": "markdown", - "id": "a306f3cb", + "id": "3627c2ef", "metadata": { - "editable": false, "slideshow": { - "slide_type": "fragment" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "Writing a csv file:" + "* Python is an object oriented programming language. Object-Oriented Programming (OOP) is a programming paradigm based on the concept of \"objects\" which can contain:\n", + " - Data (attributes)\n", + " - Code (methods)" + ] + }, + { + "cell_type": "markdown", + "id": "8393fae9", + "metadata": { + "slideshow": { + "slide_type": "slide" + }, + "tags": [], + "editable": false + }, + "source": [ + "\n", + "## 1. Classes and Objects\n", + " - Class: A blueprint for creating objects (Think a cookiecutter)\n", + " - Object: An instance of a class (The created cookies)\n", + "\n", + "\n", + "A simple example:" ] }, { "cell_type": "code", "execution_count": null, - "id": "b10a1b92", + "id": "5005c5bc", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5516,45 +5338,41 @@ }, "outputs": [], "source": [ - "import csv, math\n", + "# Simple example\n", + "class CourseParticipant:\n", + " def __init__(self, name, email):\n", + " self.name = name\n", + " self.email = email\n", "\n", - "# Read the file object\n", - "with open(\"example.csv\", 'w') as out_f:\n", - " # use csv.writer to interact\n", - " writer = csv.writer(out_f, delimiter=',')\n", - " # write the headings\n", - " writer.writerow([\"x_axis\", \"y_axis\"])\n", - " # generate the data for x\n", - " x_axis = [x * 0.1 for x in range(0, 100)]\n", - " # write x and cos(x) for every entry\n", - " for x in x_axis:\n", - " writer.writerow([x, math.cos(x)])\n", + " def welcome(self):\n", + " print(f\"Welcome {self.name}! We're glad to have you.\")\n", "\n", - "print(\"Created example.csv with x and cos(x) values\")" + "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", + "participant1.welcome()" ] }, { "cell_type": "markdown", - "id": "3a9c7b35", + "id": "b2a91e2a", "metadata": { - "editable": false, - "jp-MarkdownHeadingCollapsed": true, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "---\n", - "Now, let\u2019s extract the value for `y_axis` when `x_axis` is `1.0` for the csv we just wrote:" + "## 2. Encapsulation\n", + " - Bundling data and methods that work on that data within one unit\n", + " - Restricting access to certain details\n", + " - Is also often used to keep track of states." ] }, { "cell_type": "code", "execution_count": null, - "id": "7d2b75d2-f0a2-490e-be7d-28dad71ef05c", + "id": "74cd0847", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5562,142 +5380,143 @@ }, "outputs": [], "source": [ - "# Show the first few lines to demonstrate what we created\n", - "print(\"First few lines of the file:\")\n", - "with open(\"example.csv\", 'r') as f:\n", - " for _ in range(5):\n", - " print(f.readline().strip())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9af8c87f-62db-4a04-86d8-d51428395210", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "# Show the value of Y for X==1.0 saved in the file\n", - "print(\"The value of Y for X==1.0 saved in the file:\")\n", - "with open (\"example.csv\", 'r') as in_f:\n", - " reader = csv.reader(in_f, delimiter=',')\n", - " next(reader) # skip header\n", - " for row in reader:\n", - " if row[0] == \"1.0\":\n", - " print(row[1])\n", - " break" + "class CourseParticipant:\n", + " def __init__(self, name, email):\n", + " self.name = name\n", + " self.email = email\n", + " self.registered_attendance = False\n", + "\n", + " def welcome(self):\n", + " print(f\"Welcome {self.name}! We're glad to have you.\")\n", + "\n", + " def register_attendance(self):\n", + " self.registered_attendance = True\n", + " print(f\"{self.name} has been registered for attendance.\")\n", + "\n", + "# use the class\n", + "participant1 = CourseParticipant(\"Alice\", \"alice@example.com\")\n", + "participant1.welcome()\n", + "participant1.register_attendance()\n" ] }, { "cell_type": "markdown", - "id": "6ee8121a", + "id": "df442469", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "---" + "## 3. Inheritance\n", + " - Creating new classes that extend the functionality of existing classes\n", + " - We _inherit_ the properties of the base class `CourseParticipant`\n", + " - `super()` lets us invoke the function of the same name from the base class\n", + " - Carefully decide between inheritance and composition (see soon)" ] }, { - "cell_type": "markdown", - "id": "a00f019b", + "cell_type": "code", + "execution_count": null, + "id": "8e94ff6d", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, "tags": [] }, + "outputs": [], "source": [ - "## Building your own module\n", - "\n", - " - If you have a .py file in a path that is available to python, you can import any object defined in that file.\n", - " - If you have `mymodule.py` in your folder you can just write:\n", - "\n", - " `import mymodule`\n", + "class ExternalParticipant(CourseParticipant):\n", + " def __init__(self, name, email, company):\n", + " super().__init__(name, email)\n", + " self.company = company\n", "\n", - " and use a function defined in there with `mymodule.my_function(arg)`\n", - " - of course you can also use the method\n", + " def contact_company(self):\n", + " print(f\"Contacting {self.company} regarding course participation.\")\n", "\n", - " `from mymodule import my_function`" + "external_participant1 = ExternalParticipant(\"Bob\", \"bob@example.com\", \"Cooperative Inc.\")\n", + "external_participant1.welcome()\n", + "external_participant1.contact_company()\n" ] }, { "cell_type": "markdown", - "id": "dd9284d3-b9cc-43b1-a369-731c3e09351e", + "id": "2cf3958b", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] - }, - "source": [ - "### Simple example:" - ] - }, - { - "cell_type": "markdown", - "id": "9bdac1cc-4bdc-4a40-b4d7-25e24edc611f", - "metadata": { + "tags": [], "editable": false }, "source": [ - "Create a file called `calculator.py`:" + "## 4. Polymorphism\n", + "- Definition: Call the same method name on different object types and get type-specific behavior.\n", + "- Key idea: Write code to an interface, not a concrete class.\n", + "- Why it matters:\n", + " - Decouples caller from concrete types (extensible)\n", + " - Removes conditionals/type-checks (cleaner)\n", + " - Eases testing and substitution (mocks/fakes)" ] }, { "cell_type": "code", "execution_count": null, - "id": "9d4973db-7dbb-4a57-a027-d12de35c9d48", - "metadata": {}, + "id": "a414bc89", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "outputs": [], "source": [ - "module_path = 'calculator.py'\n", - "\n", - "module_content = \\\n", - "\"\"\"def add(a, b):\n", - " return a + b\n", - "\n", - "def multiply(a, b):\n", - " return a * b\n", + "class DurhamUniversityParticipant(CourseParticipant):\n", + " def register_attendance(self):\n", + " super().register_attendance()\n", + " print(f\" Also registered attendance with the internal additional system for {self.name}\")\n", + " \n", "\n", - "PI = 3.14159\n", - "\"\"\"\n", + "participants = [\n", + " ExternalParticipant(\"Alice\", \"alice@example.com\", \"Acme Corp\"),\n", + " DurhamUniversityParticipant(\"Bob\", \"bob@durham.ac.uk\"),\n", + " CourseParticipant(\"Charlie\", \"charlie@example.com\")\n", + "]\n", "\n", - "with open(module_path, 'w') as fobj:\n", - " fobj.write(module_content)" + "for participant in participants:\n", + " participant.register_attendance()" ] }, { "cell_type": "markdown", - "id": "a547c272-803a-46e8-af1f-00600ad11e92", + "id": "fdb800a8", "metadata": { - "editable": false, "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "Then you can use it in your main program:" + "## 5. Composition\n", + "\n", + "- Definition: Build classes by combining other objects (a class has collaborators).\n", + "- Why choose it:\n", + " - Favors flexibility and reuse over tight inheritance ties\n", + " - Swap components easily\n", + "\n", + "- If your `__init__` functions have alternative optional parameters, this is often a sign you should use composition\n", + "- Especially favour composition if there are several options for different behaviours that can be combined interchangeably (_has-a_ vs interitance: _is-a_)\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "2d3584bd-f99b-4fc8-9b19-db321634f329", + "id": "2cea837b", "metadata": { - "editable": true, "slideshow": { "slide_type": "" }, @@ -5705,128 +5524,160 @@ }, "outputs": [], "source": [ - "import calculator\n", + "class Messenger:\n", + " def send_message(self, message):\n", + " pass\n", "\n", - "result = calculator.add(5, 3)\n", - "print(f\"5 + 3 = {result}\")\n", - "print(f\"Pi is approximately {calculator.PI}\")" + "class EmailMessenger(Messenger):\n", + "\n", + " def __init__(self, email):\n", + " self.email = email\n", + "\n", + " def send_message(self, message):\n", + " print(f\"Sending email to {self.email}: {message}\")\n", + "\n", + "class TeamsMessenger(Messenger):\n", + "\n", + " def __init__(self, user_id):\n", + " self.user_id = user_id\n", + "\n", + " def send_message(self, message):\n", + " print(f\"Sending Teams message to {self.user_id}: {message}\")\n", + "\n", + "\n", + "class Participant:\n", + " def __init__(self, name, messenger):\n", + " self.name = name\n", + " self.messenger = messenger\n", + "\n", + " def welcome(self):\n", + " self.messenger.send_message(f\"Welcome {self.name}!\")\n", + "\n", + "# Use the Participant class\n", + "participants = [\n", + " Participant(\"Alice\", EmailMessenger(\"alice@example.com\")),\n", + " Participant(\"Bob\", TeamsMessenger(\"bob123\"))\n", + "]\n", + "\n", + "for participant in participants:\n", + " participant.welcome()\n" ] }, { "cell_type": "markdown", - "id": "47dd6a0c", + "id": "129df112", "metadata": { - "editable": false, - "slideshow": { - "slide_type": "slide" - }, - "tags": [] + "editable": false }, "source": [ - "### ```__main__``` special built-in variable\n", - "**Important:** When creating modules, you need to be careful about code that runs automatically. So, python files can be executed with `python mymodule.py` or loaded from with `import`.\n", - "However, all commands just put into a python file will be executed on import.\n", - "\n", - "The answer is to introduce a `__main__` block that is only executed when the file is called as a script.\n", - "It is good practice to have all code executed in a script to be either in a function or in this block." + "---" ] }, { "cell_type": "markdown", - "id": "7f4123ae", + "id": "d9c8cd20", "metadata": { - "editable": false, "slideshow": { - "slide_type": "fragment" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "\n", - "### Example content of `mymodule.py`:\n", - "```python\n", - "def myfunction():\n", - " print(\"I will be only printed when the function is called\")\n", - "\n", - "print(\"I will be called on import and execution as a script\")\n", - "\n", - "if __name__ == \"__main__\":\n", - " print(\"I will only executed when called as a script\")\n", - "```" + "## Have a play!" ] }, { "cell_type": "markdown", - "id": "bbe2196d", + "id": "28e31e47", "metadata": { - "editable": false, "slideshow": { - "slide_type": "slide" + "slide_type": "" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ - "## Have a play!\n", + "### Plant Sensor API Exercise\n", + "You've been given a virtual sensor API module which you can import with (`import sensor_api`) that can monitor plants. \n", + "The API provides three functions:\n", "\n", - "**Exercise: Create and use your own module**\n", + "- `connect(sensor_id)`: Connects to a sensor (returns True/False)\n", + "- `disconnect(sensor_id)`: Disconnects from a sensor (returns True/False) \n", + "- `send_message(message)`: Sends a command and receives a reading (returns float or None)\n", "\n", - "1. **Create the module file**: Put the example content from the previous slide into a `mymodule.py` file in your folder\n", - "2. **Import and test**: Import `myfunction` into this notebook and run it\n", - "3. **Observe the output**: Notice what gets printed when you import the module\n", - "4. **Add functionality**: Create a new function that returns the sine of a value\n", - " - *Note: You might need to restart the kernel (Kernel \u2192 Restart Kernel) if you've already imported the module*\n", - "5. **Test your addition**: Import the updated module and test your sine function\n", + "#### Message Format\n", + "Messages must be formatted as: `\"SENSOR_ID:COMMAND\"`\n", "\n", - "**Goal**: Understand how modules work, what code runs on import, and how to add your own functions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be842bd3", - "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "# solution hint, cell 1\n", - "# (In the solution writing to a module is done as code in this cell)\n", - "# Write the content into the module file:\n" + "Available commands:\n", + "- `SOIL_HUMIDITY`: Get soil humidity (0-100%)\n", + "- `AIR_HUMIDITY`: Get air humidity (0-100%)\n", + "- `TEMPERATURE`: Get temperature in Celsius\n", + "\n", + "#### Before\n", + "This is how working with the API would currently look:\n", + "\n", + "```python\n", + "import sensor_api\n", + "\n", + "sensor_id = \"GREENHOUSE_01\"\n", + "sensor_api.connect(sensor_id)\n", + "\n", + "soil_humidity = float(sensor_api.send_message(f\"{id}:SOIL_HUMIDITY\"))\n", + "air_humidity = float(sensor_api.send_message(f\"{id}:AIR_HUMIDITY\"))\n", + "temperature = float(sensor_api.send_message(f\"{id}:TEMPERATURE\"))\n", + "\n", + "print(f\"\\n=== Plant Sensor {sensor_id} Readings ===\")\n", + "print(f\"Soil Humidity: {soil_humidity}%\")\n", + "print(f\"Air Humidity: {air_humidity}%\")\n", + "print(f\"Temperature: {temperature}\u00b0C\")\n", + "print(\"=\" * 35)\n", + "sensor_api.disconnect(id)\n", + "```\n", + "\n", + "#### Your Task\n", + "Create a `PlantSensor` class that:\n", + "\n", + "1. Stores the sensor ID when created\n", + "2. Automatically connects when initialized\n", + "3. Provides easy-to-use methods for each measurement type\n", + "4. Properly disconnects when done\n", + "5. Displays all readings in a nice format\n", + "\n", + "\n", + "\n", + "#### Desired result\n", + "```python\n", + "# This is how your class should work:\n", + "sensor = PlantSensor(\"PLANT_01\")\n", + "soil = sensor.get_soil_humidity()\n", + "air = sensor.get_air_humidity()\n", + "temp = sensor.get_temperature()\n", + "sensor.display_readings()\n", + "sensor.disconnect()\n", + "```" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "506cd6b2", + "cell_type": "markdown", + "id": "9cb57fee", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", "slideshow": { - "slide_type": "" + "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, - "outputs": [], "source": [ - "# solution hint, cell 2\n", - "# Import the module:\n" + "### Implementation" ] }, { "cell_type": "code", "execution_count": null, - "id": "454b088a", + "id": "fb0d76f6", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", + "remove_code": "all", "slideshow": { "slide_type": "" }, @@ -5834,38 +5685,24 @@ }, "outputs": [], "source": [ - "# solution hint, cell 3\n", - "# Call the function from the module:\n" + "\n" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "faee9ea4", + "cell_type": "markdown", + "id": "1624a7a4", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", - "slideshow": { - "slide_type": "" - }, - "tags": [] + "editable": false }, - "outputs": [], "source": [ - "# solution hint, cell 4\n", - "# (In the solution writing to a module is done as code in this cell)\n", - "# To avoid the kernel restart, we output into a second file:\n" + "You can use this to try to use your class. You can comment out functionality, if you have not implemented it yet" ] }, { "cell_type": "code", "execution_count": null, - "id": "c8b612fa", + "id": "49d66487", "metadata": { - "editable": true, - "lines_to_next_cell": 0, - "remove_code": "non-comments", "slideshow": { "slide_type": "" }, @@ -5873,18 +5710,28 @@ }, "outputs": [], "source": [ - "# solution hint, cell 4\n", - "# Import your module and run the sine function from your own module:\n" + "my_plant = PlantSensor(\"GREENHOUSE_01\")\n", + "\n", + "# Take readings\n", + "my_plant.get_soil_humidity()\n", + "my_plant.get_air_humidity()\n", + "my_plant.get_temperature()\n", + "\n", + "# Display results\n", + "my_plant.display_readings()\n", + "\n", + "# Clean up\n", + "my_plant.disconnect()" ] }, { "cell_type": "markdown", "id": "6522c182", "metadata": { - "editable": false, "slideshow": { "slide_type": "fragment" - } + }, + "editable": false }, "source": [ "---" @@ -5894,11 +5741,11 @@ "cell_type": "markdown", "id": "ef9b73ae", "metadata": { - "editable": false, "slideshow": { "slide_type": "slide" }, - "tags": [] + "tags": [], + "editable": false }, "source": [ "# Thank You for Attending! \ud83d\udc4b\n", @@ -5932,7 +5779,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.12.3" } }, "nbformat": 4, From 8d4fef6177c9cc2ebc58ae81972dc97af068d2c9 Mon Sep 17 00:00:00 2001 From: Dmitry Nikolaenko Date: Mon, 2 Mar 2026 00:46:12 +0000 Subject: [PATCH 7/9] Drop exceptions in advanced string manipulation and restore notes slide type from skip --- Intermediate.ipynb | 123 +----------------------------- Intermediate_full.ipynb | 161 ++++++---------------------------------- 2 files changed, 26 insertions(+), 258 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index 15dd2b3..3ae6b56 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -4848,8 +4848,8 @@ }, "source": [ "These methods help you locate substrings within a string, returning their position or checking for their presence:\n", - "* `index()` - returns `-1` if the substring is not found\n", - "* `find()` - raises a `ValueError` if the substring is not found" + "* `index()`\n", + "* `find()`" ] }, { @@ -4886,38 +4886,6 @@ "print(line.find('wombat'))" ] }, - { - "cell_type": "markdown", - "id": "714fc569", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "" - } - }, - "source": [ - "The key difference is how they handle missing substrings - `find()` returns `-1` while `index()` raises an exception:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc5a28ef-8a31-434a-a653-1662cc274945", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "try:\n", - " print(line.index('wombat'))\n", - "except ValueError:\n", - " print(\"A wombat isn't mentioned in the text\")" - ] - }, { "cell_type": "markdown", "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", @@ -5106,59 +5074,6 @@ "print(f\"Cleaned: '{email}'\")" ] }, - { - "cell_type": "markdown", - "id": "2fd63835", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "These methods work with any string and don't raise exceptions, but you may want to validate the results." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8f1ceba1", - "metadata": {}, - "outputs": [], - "source": [ - "# Transforming methods don't raise exceptions, but you can validate transformed results\n", - "def process_username(username):\n", - " \"\"\"Process and validate a username.\"\"\"\n", - " if not isinstance(username, str):\n", - " raise TypeError(f\"Username must be a string, got {type(username).__name__}\")\n", - " \n", - " # Transform: strip whitespace and convert to lowercase\n", - " processed = username.strip().lower()\n", - " \n", - " # Validate the result\n", - " if not processed:\n", - " raise ValueError(\"Username cannot be empty after processing\")\n", - " \n", - " if len(processed) < 3:\n", - " raise ValueError(f\"Username must be at least 3 characters, got {len(processed)}\")\n", - " \n", - " return processed\n", - "\n", - "# Valid case\n", - "try:\n", - " result = process_username(\" JohnDoe \")\n", - " print(f\"\u2713 Processed username: '{result}'\")\n", - "except ValueError as e:\n", - " print(f\"Error: {e}\")\n", - "\n", - "# Invalid case\n", - "try:\n", - " result = process_username(\" AB \")\n", - " print(f\"\u2713 Processed username: '{result}'\")\n", - "except ValueError as e:\n", - " print(f\"Error: {e}\")" - ] - }, { "cell_type": "markdown", "id": "6cf8076f-8f50-49ae-b558-39336c323880", @@ -5258,40 +5173,6 @@ "print(\"\\n\".join(line_list))" ] }, - { - "cell_type": "markdown", - "id": "0deaf239", - "metadata": { - "editable": false, - "slideshow": { - "slide_type": "" - } - }, - "source": [ - "`join()` will raise a `TypeError` if the iterable contains non-string elements" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "225bdd40", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "flags = [16384,1048576]\n", - "\n", - "for i in range(len(flags)):\n", - " flags_str = \"+\".join(flags[i])\n", - "#flags_str = \"+\".join(str(flag) for flag in flags)\n", - "#print(flags_str)" - ] - }, { "cell_type": "markdown", "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 7e3148a..69aa54e 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -3318,11 +3318,13 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" } }, "source": [ - "_Note_: the data structure returned by `dict.items()` is of type `dict_items`,\n", + "Speaker notes:\n", + "\n", + "The data structure returned by `dict.items()` is of type `dict_items`,\n", "which is an iterable view object displaying the dictionaryโ€™s (key, value) pairs" ] }, @@ -3905,12 +3907,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" }, "tags": [] }, "source": [ - "Notes:\n", + "Speaker notes:\n", " - We are using indented blocks again\n", " - All statements in the try block will be executed one by one\n", " - If one fails, the interpreter checks whether an except block with a matching exception type exists and execute the code in there\n", @@ -3963,12 +3965,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" }, "tags": [] }, "source": [ - "Notes:\n", + "Speaker notes:\n", "- Do __not__ write out the function again, modify the original function to look like the result function\n", "- Demonstrate that you can catch the exception with a bare except\n", "- Change the function to use the `ZeroDivisionError` explicitely, to avoid catching errors we do not mean to catch" @@ -4035,12 +4037,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" }, "tags": [] }, "source": [ - "Notes:\n", + "Speaker notes:\n", "- Do __not__ write out the function again, modify the original function to look like the result function\n", "- Using the from keyword we can add an exception to the error stack.\n", "- This can be used to give additional information, that makes the error source in the input easily traceable" @@ -4094,12 +4096,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" }, "tags": [] }, "source": [ - "Notes:\n", + "Speaker notes:\n", "- Do __not__ write out the function again, modify the original function to look like the result function\n", "- It is good practice to have these checks early in a function. Nobody likes to be 10h into a script execution to then fail a validation" ] @@ -4184,12 +4186,12 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" }, "tags": [] }, "source": [ - "Notes:\n", + "Speaker notes:\n", "- Do __not__ write out the function again, modify the original function to look like the result function\n", "- Finally is often used in clean up operations." ] @@ -4675,7 +4677,7 @@ "tags": [] }, "source": [ - "Speaker notes\n", + "Speaker notes:\n", " - In this example, participants can be contacted via e-mail or Teams\n", " - The information we need for the two contact possibilities is completely independent\n", " - The specific behaviour is used by the class, but the details are not important for the class\n", @@ -5247,8 +5249,8 @@ }, "source": [ "These methods help you locate substrings within a string, returning their position or checking for their presence:\n", - "* `index()` - returns `-1` if the substring is not found\n", - "* `find()` - raises a `ValueError` if the substring is not found" + "* `index()`\n", + "* `find()`" ] }, { @@ -5291,32 +5293,15 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "" + "slide_type": "notes" } }, "source": [ + "Speaker notes:\n", + "\n", "The key difference is how they handle missing substrings - `find()` returns `-1` while `index()` raises an exception:" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc5a28ef-8a31-434a-a653-1662cc274945", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "try:\n", - " print(line.index('wombat'))\n", - "except ValueError:\n", - " print(\"A wombat isn't mentioned in the text\")" - ] - }, { "cell_type": "markdown", "id": "40d4c38b-9a07-4e49-a9b3-003dd13f129d", @@ -5353,11 +5338,13 @@ "metadata": { "editable": true, "slideshow": { - "slide_type": "skip" + "slide_type": "notes" } }, "source": [ - "**Note:** These methods are case-sensitive and never raise exceptions - they simply return `False` if the pattern doesn't match." + "Speaker notes:\n", + "\n", + "These methods are case-sensitive." ] }, { @@ -5518,59 +5505,6 @@ "print(f\"Cleaned: '{email}'\")" ] }, - { - "cell_type": "markdown", - "id": "2fd63835", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "These methods work with any string and don't raise exceptions, but you may want to validate the results." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8f1ceba1", - "metadata": {}, - "outputs": [], - "source": [ - "# Transforming methods don't raise exceptions, but you can validate transformed results\n", - "def process_username(username):\n", - " \"\"\"Process and validate a username.\"\"\"\n", - " if not isinstance(username, str):\n", - " raise TypeError(f\"Username must be a string, got {type(username).__name__}\")\n", - " \n", - " # Transform: strip whitespace and convert to lowercase\n", - " processed = username.strip().lower()\n", - " \n", - " # Validate the result\n", - " if not processed:\n", - " raise ValueError(\"Username cannot be empty after processing\")\n", - " \n", - " if len(processed) < 3:\n", - " raise ValueError(f\"Username must be at least 3 characters, got {len(processed)}\")\n", - " \n", - " return processed\n", - "\n", - "# Valid case\n", - "try:\n", - " result = process_username(\" JohnDoe \")\n", - " print(f\"โœ“ Processed username: '{result}'\")\n", - "except ValueError as e:\n", - " print(f\"Error: {e}\")\n", - "\n", - "# Invalid case\n", - "try:\n", - " result = process_username(\" AB \")\n", - " print(f\"โœ“ Processed username: '{result}'\")\n", - "except ValueError as e:\n", - " print(f\"Error: {e}\")" - ] - }, { "cell_type": "markdown", "id": "6cf8076f-8f50-49ae-b558-39336c323880", @@ -5622,19 +5556,6 @@ "print(line.split('jumped'))" ] }, - { - "cell_type": "markdown", - "id": "b21113ff", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "**Note**: `split()` never raises an exception" - ] - }, { "cell_type": "markdown", "id": "0b649711-58b1-4174-9277-2a921e6a3b6f", @@ -5683,40 +5604,6 @@ "print(\"\\n\".join(line_list))" ] }, - { - "cell_type": "markdown", - "id": "0deaf239", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - } - }, - "source": [ - "`join()` will raise a `TypeError` if the iterable contains non-string elements" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "225bdd40", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "flags = [16384,1048576]\n", - "\n", - "for i in range(len(flags)):\n", - " flags_str = \"+\".join(flags[i])\n", - "#flags_str = \"+\".join(str(flag) for flag in flags)\n", - "#print(flags_str)" - ] - }, { "cell_type": "markdown", "id": "a965b5d9-59f4-4ed5-b7e9-89f5f0bcf60f", From 44e1ffe266977bd34fb32949ee35d4d9339c026a Mon Sep 17 00:00:00 2001 From: Niolon Date: Tue, 3 Mar 2026 16:29:00 +0000 Subject: [PATCH 8/9] Update structure --- Intermediate.ipynb | 42 ++++++++++++++++++++++++----------------- Intermediate_full.ipynb | 37 ++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index 60b62f7..0e12978 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -102,13 +102,15 @@ " - [2. Data structures](#2.-Data-structures)\n", " - [3. Conditional expressions](#3.-Conditional-expressions)\n", " - [4. Comprehensions](#4.-Comprehensions)\n", - " - [5. Exceptions](#5.-Exceptions)\n", "\n", "- [Part II](#Part-II)\n", + " - [5. Exceptions](#5.-Exceptions)\n", " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", - " - [8. (Optional) Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", - " - [9. (Optional) Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" + "\n", + "- [Optional topics](#Optional-topics)\n", + " - [8. Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", + " - [9. Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] }, { @@ -3650,6 +3652,16 @@ "# your solution\n" ] }, + { + "cell_type": "markdown", + "id": "13a0e98b", + "metadata": { + "editable": false + }, + "source": [ + "# **Part II**" + ] + }, { "cell_type": "markdown", "id": "6e54d68e", @@ -3930,20 +3942,6 @@ "# Modify the function to handle unexpected values\n" ] }, - { - "cell_type": "markdown", - "id": "930a9ea5", - "metadata": { - "slideshow": { - "slide_type": "slide" - }, - "tags": [], - "editable": false - }, - "source": [ - "# **Part II**" - ] - }, { "cell_type": "markdown", "id": "ecad0562", @@ -4784,6 +4782,16 @@ "\n" ] }, + { + "cell_type": "markdown", + "id": "25f9ad8e", + "metadata": { + "editable": false + }, + "source": [ + "# **Optional Topics**" + ] + }, { "cell_type": "markdown", "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index 2ab66cd..ba8174e 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -97,13 +97,15 @@ " - [2. Data structures](#2.-Data-structures)\n", " - [3. Conditional expressions](#3.-Conditional-expressions)\n", " - [4. Comprehensions](#4.-Comprehensions)\n", - " - [5. Exceptions](#5.-Exceptions)\n", "\n", "- [Part II](#Part-II)\n", + " - [5. Exceptions](#5.-Exceptions)\n", " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", - " - [8. (Optional) Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", - " - [9. (Optional) Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" + "\n", + "- [Optional topics](#Optional-topics)\n", + " - [8. Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", + " - [9. Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] }, { @@ -3653,6 +3655,14 @@ "doubled_fruits\n" ] }, + { + "cell_type": "markdown", + "id": "13a0e98b", + "metadata": {}, + "source": [ + "# **Part II**" + ] + }, { "cell_type": "markdown", "id": "6e54d68e", @@ -4050,19 +4060,6 @@ " return 0.0" ] }, - { - "cell_type": "markdown", - "id": "930a9ea5", - "metadata": { - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "# **Part II**" - ] - }, { "cell_type": "markdown", "id": "ecad0562", @@ -4979,6 +4976,14 @@ "print(f\"\\nUnique domains found: {sorted(domains)}\")" ] }, + { + "cell_type": "markdown", + "id": "25f9ad8e", + "metadata": {}, + "source": [ + "# **Optional Topics**" + ] + }, { "cell_type": "markdown", "id": "995ee9e7-cde0-483e-84c9-9df1b3238384", From 606ad52f3084ba2bea9bb5d539142519914b48c9 Mon Sep 17 00:00:00 2001 From: Niolon Date: Tue, 3 Mar 2026 16:32:54 +0000 Subject: [PATCH 9/9] Move Thank you slide in front of Optional topics, fix link --- Intermediate.ipynb | 48 +++++++++++++++++++---------------------- Intermediate_full.ipynb | 45 +++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/Intermediate.ipynb b/Intermediate.ipynb index 0e12978..2216356 100644 --- a/Intermediate.ipynb +++ b/Intermediate.ipynb @@ -108,7 +108,7 @@ " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", "\n", - "- [Optional topics](#Optional-topics)\n", + "- [Optional topics](#Optional-Topics)\n", " - [8. Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", " - [9. Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] @@ -4782,6 +4782,27 @@ "\n" ] }, + { + "cell_type": "markdown", + "id": "586e5a27", + "metadata": { + "editable": false + }, + "source": [ + "# Thank You for Attending! \ud83d\udc4b\n", + "\n", + "- Feedback would really be appreciated.\n", + "- Check out our other training courses at ARC:\n", + " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/training-/\n", + "- RSE support by ARC at Durham University:\n", + " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/research-software-engineering/\n", + "\n", + "#### Contact\n", + "- Email: arc-rse@durham.ac.uk\n", + "\n", + "Happy Coding! \ud83d\udc0d" + ] + }, { "cell_type": "markdown", "id": "25f9ad8e", @@ -5871,31 +5892,6 @@ "source": [ "---" ] - }, - { - "cell_type": "markdown", - "id": "ef9b73ae", - "metadata": { - "slideshow": { - "slide_type": "slide" - }, - "tags": [], - "editable": false - }, - "source": [ - "# Thank You for Attending! \ud83d\udc4b\n", - "\n", - "- Feedback would really be appreciated (see the link in the email I've sent)\n", - "- Check out our other training courses at ARC:\n", - " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/training-/\n", - "- RSE support by ARC at Durham University:\n", - " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/research-software-engineering/\n", - "\n", - "#### Contact\n", - "- Email: arc-rse@durham.ac.uk\n", - "\n", - "Happy Coding! \ud83d\udc0d" - ] } ], "metadata": { diff --git a/Intermediate_full.ipynb b/Intermediate_full.ipynb index ba8174e..c4653d8 100644 --- a/Intermediate_full.ipynb +++ b/Intermediate_full.ipynb @@ -103,7 +103,7 @@ " - [6. Introduction to modules](#6.-Introduction-to-modules)\n", " - [7. Advanced string manipulation](#7.-Advanced-string-manipulation)\n", "\n", - "- [Optional topics](#Optional-topics)\n", + "- [Optional topics](#Optional-Topics)\n", " - [8. Working with modules: Examples and creating your own](#8.-(Optional)-Working-with-modules:-Examples-and-creating-your-own)\n", " - [9. Brief introduction to Object-Oriented Programming](#9.-(Optional)-Brief-introduction-to-Object-Oriented-Programming)\n" ] @@ -4976,6 +4976,25 @@ "print(f\"\\nUnique domains found: {sorted(domains)}\")" ] }, + { + "cell_type": "markdown", + "id": "586e5a27", + "metadata": {}, + "source": [ + "# Thank You for Attending! ๐Ÿ‘‹\n", + "\n", + "- Feedback would really be appreciated.\n", + "- Check out our other training courses at ARC:\n", + " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/training-/\n", + "- RSE support by ARC at Durham University:\n", + " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/research-software-engineering/\n", + "\n", + "#### Contact\n", + "- Email: arc-rse@durham.ac.uk\n", + "\n", + "Happy Coding! ๐Ÿ" + ] + }, { "cell_type": "markdown", "id": "25f9ad8e", @@ -6219,30 +6238,6 @@ "source": [ "---" ] - }, - { - "cell_type": "markdown", - "id": "ef9b73ae", - "metadata": { - "slideshow": { - "slide_type": "slide" - }, - "tags": [] - }, - "source": [ - "# Thank You for Attending! ๐Ÿ‘‹\n", - "\n", - "- Feedback would really be appreciated (see the link in the email I've sent)\n", - "- Check out our other training courses at ARC:\n", - " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/training-/\n", - "- RSE support by ARC at Durham University:\n", - " - https://www.durham.ac.uk/research/institutes-and-centres/advanced-research-computing/research-software-engineering/\n", - "\n", - "#### Contact\n", - "- Email: arc-rse@durham.ac.uk\n", - "\n", - "Happy Coding! ๐Ÿ" - ] } ], "metadata": {