summaryrefslogtreecommitdiff
path: root/notebooks/python/python_oo.ipynb
diff options
context:
space:
mode:
Diffstat (limited to 'notebooks/python/python_oo.ipynb')
-rw-r--r--notebooks/python/python_oo.ipynb87
1 files changed, 49 insertions, 38 deletions
diff --git a/notebooks/python/python_oo.ipynb b/notebooks/python/python_oo.ipynb
index ff48ca0..b56aa26 100644
--- a/notebooks/python/python_oo.ipynb
+++ b/notebooks/python/python_oo.ipynb
@@ -36,11 +36,11 @@
36 "id": "be3062ad-9437-4ba2-9975-c2837b0af9dc", 36 "id": "be3062ad-9437-4ba2-9975-c2837b0af9dc",
37 "metadata": {}, 37 "metadata": {},
38 "source": [ 38 "source": [
39 "# The big picture - the course so far\n", 39 "# The course so far\n",
40 "\n", 40 "\n",
41 "- Basics: About the language, the Python eco-system, types, modules, functions, scopes, decorators, string formatting\n", 41 "- Basics: About the language, the Python eco-system, types, modules, functions, scopes, decorators, string formatting\n",
42 "\n", 42 "\n",
43 "- **Object-oriented programming in Python: How Python \"really works\"**\n", 43 "- **Object-oriented programming in Python - How Python \"really works\": classes and objects, building / extending custom types (classes), inheritance, iterators**\n",
44 "\n", 44 "\n",
45 "- Control flow: if / for / while / try, use of iterators, \"tactical programming\" tips\n", 45 "- Control flow: if / for / while / try, use of iterators, \"tactical programming\" tips\n",
46 "\n", 46 "\n",
@@ -78,13 +78,20 @@
78 "\n", 78 "\n",
79 "The following four concepts / principles are presented in most object-oriented programming books:\n", 79 "The following four concepts / principles are presented in most object-oriented programming books:\n",
80 "\n", 80 "\n",
81 "- separate and hide \"private\" details from the outside world and / or child (inheriting) functionality (*encapsulation*) - supports *separation of concerns*\n",
82 "\n",
83 "- separate the interface from its implementation (*abstraction*)\n", 81 "- separate the interface from its implementation (*abstraction*)\n",
84 "\n", 82 "\n",
83 "- separate and hide \"private\" details from the outside world and / or child (inheriting) functionality (*encapsulation*) - supports *separation of concerns*\n",
84 "\n",
85 "- inherit and extend / adapt existing functionality, through \"is-a\" relationship hierarchy (*inheritance*)\n", 85 "- inherit and extend / adapt existing functionality, through \"is-a\" relationship hierarchy (*inheritance*)\n",
86 "\n", 86 "\n",
87 "- execute different code / functionality based on the object's place in the hierarchy (polymorphism)" 87 "- execute different code / functionality based on the object's place in the hierarchy (polymorphism)\n",
88 "\n",
89 "\n",
90 "## Difference between *abstraction* and *encapsulation*\n",
91 "\n",
92 "*Abstraction* hides complexity by giving you a more abstract picture, while *encapsulation* hides internal work so that you can change it later.\n",
93 "\n",
94 "*Abstraction* solves problems at the design level while *encapsulation* solves problems at the implementation level."
88 ] 95 ]
89 }, 96 },
90 { 97 {
@@ -210,7 +217,7 @@
210 }, 217 },
211 { 218 {
212 "cell_type": "code", 219 "cell_type": "code",
213 "execution_count": 40, 220 "execution_count": 1,
214 "id": "a9c30a5d-aa86-45ab-b897-f051df80f1d8", 221 "id": "a9c30a5d-aa86-45ab-b897-f051df80f1d8",
215 "metadata": {}, 222 "metadata": {},
216 "outputs": [ 223 "outputs": [
@@ -218,17 +225,17 @@
218 "name": "stdout", 225 "name": "stdout",
219 "output_type": "stream", 226 "output_type": "stream",
220 "text": [ 227 "text": [
221 "car1.get_obj_info_str() = \"I am <__main__.Car object at 0x7fdda86a51d0> with id 140589990040016 from <class '__main__.Car'> with id 93981278397392\"\n", 228 "car1.get_obj_info_str() = \"I am <__main__.Car object at 0x7f5630542810> with id 140008154736656 from <class '__main__.Car'> with id 94904583728688\"\n",
222 "car2.get_obj_info_str() = \"I am <__main__.Car object at 0x7fdda86c4d90> with id 140589990170000 from <class '__main__.Car'> with id 93981278397392\"\n", 229 "car2.get_obj_info_str() = \"I am <__main__.Car object at 0x7f5633ec8190> with id 140008215052688 from <class '__main__.Car'> with id 94904583728688\"\n",
223 "id(Car.cls_extras) = 140589990168000, id(Car.__init__) = 140589989979424\n", 230 "car1.model = 'BMW', car1.reg_nr = 'EC76183', car1.extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140008154734272, id(car1.__init__) = 140008154735680\n",
224 "car1.model = 'BMW', car1.reg_nr = 'EC76183', car1.extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000, id(car1.__init__) = 140589990039168\n", 231 "car2.model = 'Scoda', car2.reg_nr = 'BD77655', car2.extras = ['GPSnav'], id(car2.cls_extras) = 140008154734272, id(car2.__init__) = 140008154736768\n",
225 "car2.model = 'Scoda', car2.reg_nr = 'BD77655', car2.extras = ['GPSnav'], id(car2.cls_extras) = 140589990168000, id(car2.__init__) = 140589990039808\n", 232 "id(Car.cls_extras) = 140008154734272, id(Car.__init__) = 140008154484864\n",
226 "car1.cls_extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000\n", 233 "car1.cls_extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140008154734272\n",
227 "car2.cls_extras = ['GPSnav', 'Sound system'], id(car2.cls_extras) = 140589990168000\n", 234 "car2.cls_extras = ['GPSnav', 'Sound system'], id(car2.cls_extras) = 140008154734272\n",
228 "True\n", 235 "True\n",
229 "hasattr(car1, 'import_tax_paid') = True\n", 236 "hasattr(car1, 'import_tax_paid') = True\n",
230 "hasattr(car2, 'import_tax_paid') = False\n", 237 "hasattr(car2, 'import_tax_paid') = False\n",
231 "id(car1.__class__) = 93981278397392, id(car2.__class__) = 93981278397392, id(Car) = 93981278397392\n" 238 "id(car1.__class__) = 94904583728688, id(car2.__class__) = 94904583728688, id(Car) = 94904583728688\n"
232 ] 239 ]
233 } 240 }
234 ], 241 ],
@@ -270,9 +277,9 @@
270 "# - checks if 'attr' is a class attribute\n", 277 "# - checks if 'attr' is a class attribute\n",
271 "# - raises AttributeError\n", 278 "# - raises AttributeError\n",
272 "# setter: (re)defines an instance attribute\n", 279 "# setter: (re)defines an instance attribute\n",
273 "print(f\"{id(Car.cls_extras) = }, {id(Car.__init__) = }\")\n",
274 "print(f\"{car1.model = }, {car1.reg_nr = }, {car1.extras = }, {id(car1.cls_extras) = }, {id(car1.__init__) = }\")\n", 280 "print(f\"{car1.model = }, {car1.reg_nr = }, {car1.extras = }, {id(car1.cls_extras) = }, {id(car1.__init__) = }\")\n",
275 "print(f\"{car2.model = }, {car2.reg_nr = }, {car2.extras = }, {id(car2.cls_extras) = }, {id(car2.__init__) = }\")\n", 281 "print(f\"{car2.model = }, {car2.reg_nr = }, {car2.extras = }, {id(car2.cls_extras) = }, {id(car2.__init__) = }\")\n",
282 "print(f\"{id(Car.cls_extras) = }, {id(Car.__init__) = }\")\n",
276 "car1.cls_extras.extend(car1.extras)\n", 283 "car1.cls_extras.extend(car1.extras)\n",
277 "# car1.cls_extras = car1.extras # N.B. This will create a *NEW instance attribute* called 'cls_extras'\n", 284 "# car1.cls_extras = car1.extras # N.B. This will create a *NEW instance attribute* called 'cls_extras'\n",
278 "print(f\"{car1.cls_extras = }, {id(car1.cls_extras) = }\")\n", 285 "print(f\"{car1.cls_extras = }, {id(car1.cls_extras) = }\")\n",
@@ -298,7 +305,7 @@
298 }, 305 },
299 { 306 {
300 "cell_type": "code", 307 "cell_type": "code",
301 "execution_count": 41, 308 "execution_count": 2,
302 "id": "391e816e-c53b-454b-9e9f-3587234f1fea", 309 "id": "391e816e-c53b-454b-9e9f-3587234f1fea",
303 "metadata": {}, 310 "metadata": {},
304 "outputs": [ 311 "outputs": [
@@ -388,7 +395,7 @@
388 }, 395 },
389 { 396 {
390 "cell_type": "code", 397 "cell_type": "code",
391 "execution_count": 42, 398 "execution_count": 3,
392 "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c", 399 "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c",
393 "metadata": {}, 400 "metadata": {},
394 "outputs": [ 401 "outputs": [
@@ -470,7 +477,7 @@
470 }, 477 },
471 { 478 {
472 "cell_type": "code", 479 "cell_type": "code",
473 "execution_count": 43, 480 "execution_count": 4,
474 "id": "71a90ec6-3cc0-441e-a866-c2c2b9984559", 481 "id": "71a90ec6-3cc0-441e-a866-c2c2b9984559",
475 "metadata": {}, 482 "metadata": {},
476 "outputs": [ 483 "outputs": [
@@ -478,9 +485,9 @@
478 "name": "stdout", 485 "name": "stdout",
479 "output_type": "stream", 486 "output_type": "stream",
480 "text": [ 487 "text": [
481 "my_first_vector = Vector(start=<Point(x=0, y=0)>, end=<Point(x=9, y=12)>)\n", 488 "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=9, y=12))\n",
482 "my_first_vector = Vector(start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>)\n", 489 "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n",
483 "other_vector = Vector(start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>)\n", 490 "other_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n",
484 "other_vector.length = Decimal('16.97056274847714058562026469')\n", 491 "other_vector.length = Decimal('16.97056274847714058562026469')\n",
485 "True\n", 492 "True\n",
486 "True\n", 493 "True\n",
@@ -502,7 +509,7 @@
502 " self._x = x\n", 509 " self._x = x\n",
503 " self._y = y\n", 510 " self._y = y\n",
504 "\n", 511 "\n",
505 " def __bool__(self):\n", 512 " def __bool__(self) -> bool:\n",
506 " \"\"\"\n", 513 " \"\"\"\n",
507 " Called to implement truth value testing and the built-in operation\n", 514 " Called to implement truth value testing and the built-in operation\n",
508 " bool(); should return False or True. When this method is not defined,\n", 515 " bool(); should return False or True. When this method is not defined,\n",
@@ -529,7 +536,7 @@
529 "\n", 536 "\n",
530 " # \"fix\" self.__y -> self._y\n", 537 " # \"fix\" self.__y -> self._y\n",
531 " def __repr__(self) -> str:\n", 538 " def __repr__(self) -> str:\n",
532 " return f\"<Point(x={self._x!r}, y={self._y!r})>\"\n", 539 " return f\"Point(x={self._x!r}, y={self._y!r})\"\n",
533 "\n", 540 "\n",
534 " def __str__(self) -> str:\n", 541 " def __str__(self) -> str:\n",
535 " return f\"{self._x}:{self._y}\"\n", 542 " return f\"{self._x}:{self._y}\"\n",
@@ -588,7 +595,7 @@
588 }, 595 },
589 { 596 {
590 "cell_type": "code", 597 "cell_type": "code",
591 "execution_count": 44, 598 "execution_count": 5,
592 "id": "a4d2735d-d167-4f43-ad55-cb3d13ece2dc", 599 "id": "a4d2735d-d167-4f43-ad55-cb3d13ece2dc",
593 "metadata": {}, 600 "metadata": {},
594 "outputs": [ 601 "outputs": [
@@ -596,7 +603,7 @@
596 "name": "stdout", 603 "name": "stdout",
597 "output_type": "stream", 604 "output_type": "stream",
598 "text": [ 605 "text": [
599 "list(vector) = [<Point(x=1, y=1)>, <Point(x=4, y=6)>]\n", 606 "list(vector) = [Point(x=1, y=1), Point(x=4, y=6)]\n",
600 "1:1\n", 607 "1:1\n",
601 "4:6\n", 608 "4:6\n",
602 "Exhausted\n" 609 "Exhausted\n"
@@ -631,7 +638,7 @@
631 }, 638 },
632 { 639 {
633 "cell_type": "code", 640 "cell_type": "code",
634 "execution_count": 45, 641 "execution_count": 6,
635 "id": "a6ead5e6-e987-4bda-bf48-30f91877278d", 642 "id": "a6ead5e6-e987-4bda-bf48-30f91877278d",
636 "metadata": {}, 643 "metadata": {},
637 "outputs": [ 644 "outputs": [
@@ -662,7 +669,7 @@
662 " protocol via __getitem__(), see this section in the language\n", 669 " protocol via __getitem__(), see this section in the language\n",
663 " reference.\n", 670 " reference.\n",
664 " \"\"\"\n", 671 " \"\"\"\n",
665 " # ont of the following two strategies may be employed:\n", 672 " # one of the following two strategies may be employed:\n",
666 " # return point is self._start or point is self._end\n", 673 " # return point is self._start or point is self._end\n",
667 " # return point == self._start or point == self._end\n", 674 " # return point == self._start or point == self._end\n",
668 " return point == self._start or point == self._end\n", 675 " return point == self._start or point == self._end\n",
@@ -690,7 +697,7 @@
690 }, 697 },
691 { 698 {
692 "cell_type": "code", 699 "cell_type": "code",
693 "execution_count": 46, 700 "execution_count": 7,
694 "id": "11f6a3fb-64d7-40a9-a130-27548ec4b802", 701 "id": "11f6a3fb-64d7-40a9-a130-27548ec4b802",
695 "metadata": {}, 702 "metadata": {},
696 "outputs": [ 703 "outputs": [
@@ -699,9 +706,9 @@
699 "output_type": "stream", 706 "output_type": "stream",
700 "text": [ 707 "text": [
701 "__mul__ called\n", 708 "__mul__ called\n",
702 "vector * 3 = Vector(start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>)\n", 709 "vector * 3 = Vector(start=Point(x=2, y=2), end=Point(x=12, y=18))\n",
703 "__rmul__ called\n", 710 "__rmul__ called\n",
704 "3 * vector = Vector(start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>)\n" 711 "3 * vector = Vector(start=Point(x=2, y=2), end=Point(x=12, y=18))\n"
705 ] 712 ]
706 } 713 }
707 ], 714 ],
@@ -727,6 +734,8 @@
727 " return self._start\n", 734 " return self._start\n",
728 " if key in (\"end\", 1):\n", 735 " if key in (\"end\", 1):\n",
729 " return self._end\n", 736 " return self._end\n",
737 " if isinstance(key, int):\n",
738 " raise IndexError\n",
730 " raise KeyError\n", 739 " raise KeyError\n",
731 "\n", 740 "\n",
732 " def __mul__(self, other):\n", 741 " def __mul__(self, other):\n",
@@ -757,7 +766,7 @@
757 " returns NotImplemented.\n", 766 " returns NotImplemented.\n",
758 " \"\"\"\n", 767 " \"\"\"\n",
759 " print(\"__rmul__ called\")\n", 768 " print(\"__rmul__ called\")\n",
760 " return Vector(self._start, Point(self._end.x * other, self._end.y * other))\n", 769 " return Vector(self._start, Point(self._end.x * other, self._end.y * other)) # self.__class__ may be used instead of Vector???\n",
761 "\n", 770 "\n",
762 " # __rmul__ = __mul__\n", 771 " # __rmul__ = __mul__\n",
763 "\n", 772 "\n",
@@ -768,7 +777,7 @@
768 }, 777 },
769 { 778 {
770 "cell_type": "code", 779 "cell_type": "code",
771 "execution_count": 47, 780 "execution_count": 8,
772 "id": "c345a69f-02da-40e7-bb37-c0511b6af096", 781 "id": "c345a69f-02da-40e7-bb37-c0511b6af096",
773 "metadata": {}, 782 "metadata": {},
774 "outputs": [ 783 "outputs": [
@@ -777,7 +786,7 @@
777 "output_type": "stream", 786 "output_type": "stream",
778 "text": [ 787 "text": [
779 "9\n", 788 "9\n",
780 "Vector.from_str('1:1:5:6') = Vector(start=<Point(x=1, y=1)>, end=<Point(x=5, y=6)>)\n" 789 "Vector.from_str('1:1:5:6') = Vector(start=Point(x=1, y=1), end=Point(x=5, y=6))\n"
781 ] 790 ]
782 } 791 }
783 ], 792 ],
@@ -789,6 +798,8 @@
789 " @staticmethod\n", 798 " @staticmethod\n",
790 " def get_manhattan_distance(point1: Point, point2: Point) -> int:\n", 799 " def get_manhattan_distance(point1: Point, point2: Point) -> int:\n",
791 " \"\"\"Returns the Manhattan distance of two points\"\"\"\n", 800 " \"\"\"Returns the Manhattan distance of two points\"\"\"\n",
801 " # usually this will be a regular method of type:\n",
802 " # def get_manhattan_distance(self, other: Point) -> int:\n",
792 " return abs(point1.x - point2.x) + abs(point1.y - point2.y)\n", 803 " return abs(point1.x - point2.x) + abs(point1.y - point2.y)\n",
793 "\n", 804 "\n",
794 "\n", 805 "\n",
@@ -859,7 +870,7 @@
859 }, 870 },
860 { 871 {
861 "cell_type": "code", 872 "cell_type": "code",
862 "execution_count": 48, 873 "execution_count": 9,
863 "id": "44d47e1c-1a06-4577-8db6-6ec78ce5cef8", 874 "id": "44d47e1c-1a06-4577-8db6-6ec78ce5cef8",
864 "metadata": {}, 875 "metadata": {},
865 "outputs": [ 876 "outputs": [
@@ -1033,7 +1044,7 @@
1033 }, 1044 },
1034 { 1045 {
1035 "cell_type": "code", 1046 "cell_type": "code",
1036 "execution_count": 49, 1047 "execution_count": 10,
1037 "id": "e6076925-75f0-456c-aed5-7db0a24a67a1", 1048 "id": "e6076925-75f0-456c-aed5-7db0a24a67a1",
1038 "metadata": {}, 1049 "metadata": {},
1039 "outputs": [ 1050 "outputs": [
@@ -1144,7 +1155,7 @@
1144 }, 1155 },
1145 { 1156 {
1146 "cell_type": "code", 1157 "cell_type": "code",
1147 "execution_count": 50, 1158 "execution_count": 11,
1148 "id": "cf79617a-95d2-48f2-be66-fa1fa34e4e04", 1159 "id": "cf79617a-95d2-48f2-be66-fa1fa34e4e04",
1149 "metadata": {}, 1160 "metadata": {},
1150 "outputs": [ 1161 "outputs": [
@@ -1223,7 +1234,7 @@
1223 }, 1234 },
1224 { 1235 {
1225 "cell_type": "code", 1236 "cell_type": "code",
1226 "execution_count": 51, 1237 "execution_count": 12,
1227 "id": "95a1d0cc-0006-4ddc-b08d-d0b8b02acfba", 1238 "id": "95a1d0cc-0006-4ddc-b08d-d0b8b02acfba",
1228 "metadata": {}, 1239 "metadata": {},
1229 "outputs": [ 1240 "outputs": [
@@ -1289,7 +1300,7 @@
1289 }, 1300 },
1290 { 1301 {
1291 "cell_type": "code", 1302 "cell_type": "code",
1292 "execution_count": 52, 1303 "execution_count": 13,
1293 "id": "38066107-0190-4383-ba14-a4e9cd454a9c", 1304 "id": "38066107-0190-4383-ba14-a4e9cd454a9c",
1294 "metadata": {}, 1305 "metadata": {},
1295 "outputs": [ 1306 "outputs": [