8000 Expand OOP introductory notebook (#213) · DagaEMPA/python-tutorial@ffbc6c8 · GitHub
[go: up one dir, main page]

Skip to content

Commit ffbc6c8

Browse files
despadamdespadamedoardob90
authored
Expand OOP introductory notebook (empa-scientific-it#213)
Co-authored-by: despadam <despina.adamopoulou@empa.ch> Co-authored-by: Edoardo Baldi <edoardo.baldi@empa.ch>
1 parent 823c146 commit ffbc6c8

File tree

3 files changed

+363
-150
lines changed

3 files changed

+363
-150
lines changed

object_oriented_programming.ipynb

Lines changed: 142 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@
1414
"metadata": {},
1515
"source": [
1616
"# Table of Contents\n",
17-
"\n",
18-
"- [References](#References)\n",
19-
"- [A `class` as a blueprint of objects](#A-class-as-a-blueprint-of-objects)\n",
20-
"- [Properties and methods](#Properties-and-methods)\n",
21-
"- [Python's *special methods*](#Python's-*special-methods*)\n",
22-
" - [`__str__` and `__repr__`](#__str__-and-__repr__)\n",
23-
" - [Exercise 1: Ice cream scoop 🌶️](#Exercise-1:-Ice-cream-scoop-🌶️)\n",
24-
" - [Comparison methods](#Comparison-methods)\n",
25-
" - [Exercise 2: Ice cream bowl 🌶️🌶️](#Exercise-2:-Ice-cream-bowl-🌶️🌶️)\n",
26-
"- [The `@property` keyword](#The-@property-keyword)\n",
27-
"- [Quick glossary](#Quick-glossary)\n",
28-
"- [Exercise 3: Intcode computer 🌶️🌶️🌶️](#Exercise-3:-Intcode-computer-🌶️🌶️🌶️)"
17+
" - [Object-oriented Programming](#Object-oriented-Programming)\n",
18+
" - [References](#References)\n",
19+
" - [A `class` as a blueprint of objects](#A-class-as-a-blueprint-of-objects)\n",
20+
" - [Properties and methods](#Properties-and-methods)\n",
21+
" - [Python's *special methods*](#Python's-*special-methods*)\n",
22+
" - [`__str__` and `__repr__`](#__str__-and-__repr__)\n",
23+
" - [Exercise 1: Ice cream scoop 🌶️](#Exercise-1:-Ice-cream-scoop-🌶️)\n",
24+
" - [Exercise 2: Ice cream bowl 🌶️🌶️](#Exercise-2:-Ice-cream-bowl-🌶️🌶️)\n",
25+
" - [Comparison methods](#Comparison-methods)\n",
26+
" - [Exercise 3: Ice cream shop 🌶️🌶️🌶️](#Exercise-3:-Ice-cream-shop-🌶️🌶️🌶️)\n",
27+
" - [The `@property` keyword](#The-@property-keyword)\n",
28+
" - [Quick glossary](#Quick-glossary)\n",
29+
" - [Quiz](#Quiz)\n",
30+
" - [Exercise 4: Intcode computer 🌶️🌶️🌶️🌶️](#Exercise-4:-Intcode-computer-🌶️🌶️🌶️🌶️)"
2931
]
3032
},
3133
{
@@ -270,7 +272,7 @@
270272
"id": "0f394fcf-6dca-4867-b098-51e97adcd268",
271273
"metadata": {},
272274
"source": [
273-
"Special methods are methods that Python define automatically. If you define a custom class, then you are responsible of definining the **expected behavior** of these methods. Otherwise, Python will fallback to the default, built-in definition, or it will raise an error if it doesn't know what to do.\n",
275+
"Special methods are methods that Python defines automatically. If you define a custom class, then you are responsible of defining the **expected behavior** of these methods. Otherwise, Python will fallback to the default, built-in definition, or it will raise an error if it doesn't know what to do.\n",
274276
"\n",
275277
"These are also called **dunder methods**, that is, \"double-underscore methods\", because their names look like `__method__`. There are special **attributes** as well."
276278
]
@@ -478,7 +480,7 @@
478480
"id": "0d793886-49fd-4300-87e5-664fc7a3eb3c",
479481
"metadata": {},
480482
"source": [
481-
"As you can see we still get that default. That's because here Python is **not** converting `r1` to a string, but instead looking for a string *representation* of the object. It is looking for the [`__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), which is defined as\n",
483+
"As you can see we still get the default. That's because here Python is **not** converting `r1` to a string, but instead looking for a string *representation* of the object. It is looking for the [`__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), which is defined as\n",
482484
"\n",
483485
"> the “official” string representation of an object\n",
484486
"\n",
@@ -543,7 +545,7 @@
543545
"\n",
544546
"<div class=\"alert alert-block alert-warning\">\n",
545547
" <h4><b>Question</b></h4>\n",
546-
" Complete the solution function such that it creates <strong>three</strong> instances of the <code>Scoop</code> class with the following flavors: chocolate, vanilla, persimmon. This function should return a list that collects the <strong>string representations</strong> of the ice cream scoops.\n",
548+
" Complete the solution function such that it creates an instance of the <code>Scoop</code> class for every flavor contained in the argument <code>flavors</code>. This function should return a list that collects the <strong>string representations</strong> of the ice cream scoops.\n",
547549
"</div>"
548550
]
549551
},
@@ -557,14 +559,70 @@
557559
"outputs": [],
558560
"source": [
559561
"%%ipytest\n",
560-
"class Scoop:\n",
561-
" \"\"\"A class representing a single scoop of ice cream\"\"\"\n",
562-
" # Write your class implementation here\n",
563562
"\n",
563+
"def solution_ice_cream_scoop(flavors: tuple[str]) -> list[str]:\n",
564564
"\n",
565-
"flavors = # TODO: create a tuple containing the flavors\n",
565+
" class Scoop:\n",
566+
" \"\"\"A class representing a single scoop of ice cream\"\"\"\n",
567+
" # Write your class implementation here\n",
568+
"\n",
569+
" # Write your solution here\n",
570+
" pass"
571+
]
572+
},
573+
{
574+
"cell_type": "markdown",
575+
"id": "4abfe0ba-c893-4ffd-b40b-5931821bcc62",
576+
"metadata": {
577+
"tags": []
578+
},
579+
"source": [
580+
"### Exercise 2: Ice cream bowl 🌶️🌶️"
581+
]
582+
},
583+
{
584+
"cell_type": "markdown",
585+
"id": "7f366029-6fa1-48f9-95ee-578b02addecd",
586+
"metadata": {},
587+
"source": [
588+
"Create a class `Bowl` that can hold many ice cream scoops, as many as you like. You *should use* the custom class you created in the previous exercise.\n",
589+
"\n",
590+
"The `Bowl` class should have a method called `add_scoops()` that accepts **variable number** of scoops.\n",
591+
"\n",
592+
"<div class=\"alert alert-block alert-info\">\n",
593+
" <h4><b>Hint</b></h4>\n",
594+
" In the <code>__init__</code> method of the <code>Bowl</code> class, you should define an attribute that acts as a container to hold the scoops you might want to add.\n",
595+
"</div>\n",
596+
"\n",
597+
"<div class=\"alert alert-block alert-warning\">\n",
598+
" <h4><b>Question</b></h4> \n",
599+
" Complete the solution function such that it creates a bowl of scoops with every flavor contained in the argument <code>flavors</code>. The output of this function should be a <strong>string</strong> that reports the content of the bowl you just created.\n",
600+
"</div>\n",
601+
"\n",
602+
"For example:\n",
603+
"\n",
604+
"```\n",
605+
"Ice cream bowl with chocolate, vanilla, stracciatella scoops\n",
606+
"```"
607+
]
608+
},
609+
{
610+
"cell_type": "code",
611+
"execution_count": null,
612+
"id": "0a634345-9799-4d1d-967b-9634c5672e5f",
613+
"metadata": {
614+
"tags": []
615+
},
616+
"outputs": [],
617+
"source": [
618+
"%%ipytest\n",
619+
" \n",
620+
"def solution_ice_cream_bowl(flavors: tuple[str]) -> str:\n",
621+
"\n",
622+
" class Bowl:\n",
623+
" \"\"\"A class representing a bowl of ice cream scoops\"\"\"\n",
624+
" # Write your class implementation here\n",
566625
"\n",
567-
"def solution_ice_cream_scoop(flavors: tuple[str]) -> list[str]:\n",
568626
" # Write your solution here\n",
569627
" pass"
570628
]
@@ -766,7 +824,7 @@
766824
"id": "72254316-200d-4a6d-bf93-d669f041c08b",
767825
"metadata": {},
768826
"source": [
769-
"That's because our `Rectangle` class automatically return `False` if we try to compare for equality an instance of `Rectangle` and any other Python object"
827+
"That's because our `Rectangle` class automatically returns `False` if we try to compare for equality an instance of `Rectangle` and any other Python object."
770828
]
771829
},
772830
{
@@ -951,58 +1009,50 @@
9511009
},
9521010
{
9531011
"cell_type": "markdown",
954-
"id": "4abfe0ba-c893-4ffd-b40b-5931821bcc62",
955-
"metadata": {
956-
"tags": []
957-
},
1012+
"id": "af6a4710",
1013+
"metadata": {},
9581014
"source": [
959-
"### Exercise 2: Ice cream bowl 🌶️🌶️"
1015+
"### Exercise 3: Ice cream shop 🌶️🌶️🌶️"
9601016
]
9611017
},
9621018
{
9631019
"cell_type": "markdown",
964-
"id": "7f366029-6fa1-48f9-95ee-578b02addecd",
1020+
"id": "883794ff",
9651021
"metadata": {},
9661022
"source": [
967-
"Create a class `Bowl` that can hold many ice cream scoops, as many as you like. You *should use* the custom class you created in the previous exercise.\n",
1023+
"Create a class `Shop` that sells many ice cream flavours. \n",
9681024
"\n",
969-
"The `Bowl` class should have a method called `add_scoops()` that accept **variable number** of scoops.\n",
1025+
"The `Shop` class should implement the comparison methods `__eq__`, `__lt__`, `__le__`.\n",
9701026
"\n",
9711027
"<div class=\"alert alert-block alert-info\">\n",
972-
" <h4><b>Hint</b></h4>\n",
973-
" In the <code>__init__</code> method of the <code>Bowl</code> class, you should define an attribute that acts as a container to hold the scoops you might want to add\n",
1028+
" <h4><b>Hints</b></h4>\n",
1029+
" <ul>\n",
1030+
" <li>In the <code>__init__</code> method of the <code>Shop</code> class, you should define an attribute that acts as a container to hold the available flavours.</li>\n",
1031+
" <li>You can use <code>__eq__</code> and <code>__lt__</code> to define <code>__le__</code>.</li>\n",
1032+
" </ul>\n",
9741033
"</div>\n",
9751034
"\n",
9761035
"<div class=\"alert alert-block alert-warning\">\n",
9771036
" <h4><b>Question</b></h4> \n",
978-
" Complete the solution function that creates a bowl of three scoops with flavors chocolate, vanilla, and stracciatella. The output of this function should be a <strong>string</strong> that reports the content of the bowl just created.\n",
979-
"</div>\n",
980-
"\n",
981-
"For example:\n",
982-
"\n",
983-
"```\n",
984-
"Ice cream bowl with chocolate, vanilla, stracciatella scoops\n",
985-
"```"
1037+
" Complete the solution function so that it creates two ice cream shops. <code>Shop 1</code> should sell the flavors provided by the parameter <code>flavor_1</code> and <code>Shop 2</code> should sell the flavors provided by the parameter <code>flavor_2</code>. The output of this function should be a <strong>boolean value</strong>: Does <code>Shop 1</code> sell <strong>fewer or the same</strong> number of flavors as <code>Shop 2</code>?\n",
1038+
"</div>"
9861039
]
9871040
},
9881041
{
9891042
"cell_type": "code",
9901043
"execution_count": null,
991-
"id": "0a634345-9799-4d1d-967b-9634c5672e5f",
992-
"metadata": {
993-
"tags": []
994-
},
1044+
"id": "2f203841",
1045+
"metadata": {},
9951046
"outputs": [],
9961047
"source": [
9971048
"%%ipytest\n",
998-
"class Bowl:\n",
999-
" \"\"\"A class representing a bowl of ice cream scoops\"\"\"\n",
1000-
" # Write your class implementation here\n",
10011049
"\n",
1050+
"def solution_ice_cream_shop(flavors_1: list[str], flavors_2: list[str]) -> bool:\n",
1051+
"\n",
1052+
" class Shop:\n",
1053+
" \"\"\"A class representing an ice cream shop\"\"\"\n",
1054+
" # Write your class implementation here\n",
10021055
"\n",
1003-
"flavors = # TODO: create a tuple containing the flavors\n",
1004-
" \n",
1005-
"def solution_ice_cream_bowl(flavors: tuple[str]) -> str:\n",
10061056
" # Write your solution here\n",
10071057
" pass"
10081058
]
@@ -1165,14 +1215,42 @@
11651215
"---"
11661216
]
11671217
},
1218+
{
1219+
"cell_type": "markdown",
1220+
"id": "027ae22c",
1221+
"metadata": {},
1222+
"source": [
1223+
"## Quiz\n",
1224+
"\n",
1225+
"Run the following cell to test your knowledge with a small quiz."
1226 F438 +
]
1227+
},
1228+
{
1229+
"cell_type": "code",
1230+
"execution_count": null,
1231+
"id": "da20c27f",
1232+
"metadata": {},
1233+
"outputs": [],
1234+
"source": [
1235+
"from tutorial import object_oriented_programming as oop\n",
1236+
"\n",
1237+
"oop.OopQuiz()"
1238+
]
1239+
},
11681240
{
11691241
"cell_type": "markdown",
11701242
"id": "419b5378-ff17-4ed3-8203-97c132918cb7",
11711243
"metadata": {
11721244
"tags": []
11731245
},
11741246
"source": [
1175-
"## Exercise 3: Intcode computer 🌶️🌶️🌶️"
1247+
"## Exercise 4: Intcode computer 🌶️🌶️🌶️🌶️\n",
1248+
"\n",
1249+
"<div class=\"alert alert-block alert-danger\">\n",
1250+
" <h4><b>Note</b></h4>\n",
1251+
" This is a recap exercise of intermediate difficulty.\n",
1252+
" If you <strong>never</strong> used classes or objects before, please try to solve and understand the previous exercises first.\n",
1253+
"</div>"
11761254
]
11771255
},
11781256
{
@@ -1273,16 +1351,23 @@
12731351
},
12741352
"outputs": [],
12751353
"source": [
1276-
"%%ipytest\n",
1277-
"class Computer:\n",
1278-
" \"\"\"An Intcode computer class\"\"\"\n",
1279-
" # Write your class implementation here\n",
1280-
"\n",
1281-
" \n",
1354+
"%%ipytest \n",
12821355
"def solution_intcode_computer(intcode: str) -> int:\n",
1356+
" class Computer:\n",
1357+
" \"\"\"An Intcode computer class\"\"\"\n",
1358+
" # Write your class implementation here\n",
1359+
"\n",
12831360
" # Write your solution function here\n",
12841361
" pass"
12851362
]
1363+
},
1364+
{
1365+
"cell_type": "code",
1366+
"execution_count": null,
1367+
"id": "d107aab6-4225-4407-8613-19d74407c41a",
1368+
"metadata": {},
1369+
"outputs": [],
1370+
"source": []
12861371
}
12871372
],
12881373
"metadata": {
@@ -1301,7 +1386,7 @@
13011386
"name": "python",
13021387
"nbconvert_exporter": "python",
13031388
"pygments_lexer": "ipython3",
1304-
"version": "3.10.14"
1389+
"version": "3.10.13"
13051390
}
13061391
},
13071392
"nbformat": 4,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from .common import Question, Quiz
2+
3+
4+
class OopQuiz(Quiz):
5+
def __init__(self, title=""):
6+
q1 = Question(
7+
question="Based on what you learned about Python's special methods, which of the following statements is <strong>true</strong>?",
8+
options={
9+
"__repr__ is also used for __str__, but not vice versa.": "Correct! This statement is true.",
10+
"__str__ is also used for __repr__, but not vice versa.": "The opposite is true.",
11+
"__repr__ and __str__ are completely independent.": "__repr__ is also used for __str__, but not vice versa.",
12+
},
13+
correct_answer="__repr__ is also used for __str__, but not vice versa.",
14+
hint="",
15+
shuffle=True,
16+
)
17+
18+
q2 = Question(
19+
question="Based on what you learned about Python's comparison methods, which of the following statements is <strong>false</strong>?",
20+
options={
21+
"If we implement __gt__, Python will also use it for __lt__": "This statement is true.",
22+
"If we implement __lt__, Python will also use it for __le__": "Correct! This statement is false.",
23+
"If we implement __eq__, Python will also use it for __ne__": "This statement is true.",
24+
},
25+
correct_answer="If we implement __lt__, Python will also use it for __le__",
26+
hint="",
27+
shuffle=True,
28+
)
29+
30+
q3 = Question(
31+
question="Based on what you learned about the @property keyword, which of the following statements is <strong>false</strong>?",
32+
options={
33+
"@property creates attributes that act like methods but can be accessed and assigned as regular attributes.": "This statement is true.",
34+
"@property helps implement attributes that require additional logic or validation when getting or setting their values.": "This statement is true.",
35+
"@property makes code more readable but restricts dynamic attibute behaviour.": "Correct! This statement is false.",
36+
},
37+
correct_answer="@property makes code more readable but restricts dynamic attibute behaviour.",
38+
hint="",
39+
shuffle=True,
40+
)
41+
42+
super().__init__(questions=[q1, q2, q3])

0 commit comments

Comments
 (0)
0