diff options
Diffstat (limited to 'notebooks/python/python_oo.ipynb')
| -rw-r--r-- | notebooks/python/python_oo.ipynb | 87 |
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": [ |
