From a33898d9db2f0e0e9b3da6f1b329b4045b65af11 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Mon, 19 Dec 2022 05:51:15 +0100 Subject: Update notebooks/python/python_oo.ipynb --- notebooks/python/python_oo.ipynb | 87 ++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 38 deletions(-) (limited to 'notebooks') 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 @@ "id": "be3062ad-9437-4ba2-9975-c2837b0af9dc", "metadata": {}, "source": [ - "# The big picture - the course so far\n", + "# The course so far\n", "\n", "- Basics: About the language, the Python eco-system, types, modules, functions, scopes, decorators, string formatting\n", "\n", - "- **Object-oriented programming in Python: How Python \"really works\"**\n", + "- **Object-oriented programming in Python - How Python \"really works\": classes and objects, building / extending custom types (classes), inheritance, iterators**\n", "\n", "- Control flow: if / for / while / try, use of iterators, \"tactical programming\" tips\n", "\n", @@ -78,13 +78,20 @@ "\n", "The following four concepts / principles are presented in most object-oriented programming books:\n", "\n", - "- separate and hide \"private\" details from the outside world and / or child (inheriting) functionality (*encapsulation*) - supports *separation of concerns*\n", - "\n", "- separate the interface from its implementation (*abstraction*)\n", "\n", + "- separate and hide \"private\" details from the outside world and / or child (inheriting) functionality (*encapsulation*) - supports *separation of concerns*\n", + "\n", "- inherit and extend / adapt existing functionality, through \"is-a\" relationship hierarchy (*inheritance*)\n", "\n", - "- execute different code / functionality based on the object's place in the hierarchy (polymorphism)" + "- execute different code / functionality based on the object's place in the hierarchy (polymorphism)\n", + "\n", + "\n", + "## Difference between *abstraction* and *encapsulation*\n", + "\n", + "*Abstraction* hides complexity by giving you a more abstract picture, while *encapsulation* hides internal work so that you can change it later.\n", + "\n", + "*Abstraction* solves problems at the design level while *encapsulation* solves problems at the implementation level." ] }, { @@ -210,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 1, "id": "a9c30a5d-aa86-45ab-b897-f051df80f1d8", "metadata": {}, "outputs": [ @@ -218,17 +225,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "car1.get_obj_info_str() = \"I am <__main__.Car object at 0x7fdda86a51d0> with id 140589990040016 from with id 93981278397392\"\n", - "car2.get_obj_info_str() = \"I am <__main__.Car object at 0x7fdda86c4d90> with id 140589990170000 from with id 93981278397392\"\n", - "id(Car.cls_extras) = 140589990168000, id(Car.__init__) = 140589989979424\n", - "car1.model = 'BMW', car1.reg_nr = 'EC76183', car1.extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000, id(car1.__init__) = 140589990039168\n", - "car2.model = 'Scoda', car2.reg_nr = 'BD77655', car2.extras = ['GPSnav'], id(car2.cls_extras) = 140589990168000, id(car2.__init__) = 140589990039808\n", - "car1.cls_extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000\n", - "car2.cls_extras = ['GPSnav', 'Sound system'], id(car2.cls_extras) = 140589990168000\n", + "car1.get_obj_info_str() = \"I am <__main__.Car object at 0x7f5630542810> with id 140008154736656 from with id 94904583728688\"\n", + "car2.get_obj_info_str() = \"I am <__main__.Car object at 0x7f5633ec8190> with id 140008215052688 from with id 94904583728688\"\n", + "car1.model = 'BMW', car1.reg_nr = 'EC76183', car1.extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140008154734272, id(car1.__init__) = 140008154735680\n", + "car2.model = 'Scoda', car2.reg_nr = 'BD77655', car2.extras = ['GPSnav'], id(car2.cls_extras) = 140008154734272, id(car2.__init__) = 140008154736768\n", + "id(Car.cls_extras) = 140008154734272, id(Car.__init__) = 140008154484864\n", + "car1.cls_extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140008154734272\n", + "car2.cls_extras = ['GPSnav', 'Sound system'], id(car2.cls_extras) = 140008154734272\n", "True\n", "hasattr(car1, 'import_tax_paid') = True\n", "hasattr(car2, 'import_tax_paid') = False\n", - "id(car1.__class__) = 93981278397392, id(car2.__class__) = 93981278397392, id(Car) = 93981278397392\n" + "id(car1.__class__) = 94904583728688, id(car2.__class__) = 94904583728688, id(Car) = 94904583728688\n" ] } ], @@ -270,9 +277,9 @@ "# - checks if 'attr' is a class attribute\n", "# - raises AttributeError\n", "# setter: (re)defines an instance attribute\n", - "print(f\"{id(Car.cls_extras) = }, {id(Car.__init__) = }\")\n", "print(f\"{car1.model = }, {car1.reg_nr = }, {car1.extras = }, {id(car1.cls_extras) = }, {id(car1.__init__) = }\")\n", "print(f\"{car2.model = }, {car2.reg_nr = }, {car2.extras = }, {id(car2.cls_extras) = }, {id(car2.__init__) = }\")\n", + "print(f\"{id(Car.cls_extras) = }, {id(Car.__init__) = }\")\n", "car1.cls_extras.extend(car1.extras)\n", "# car1.cls_extras = car1.extras # N.B. This will create a *NEW instance attribute* called 'cls_extras'\n", "print(f\"{car1.cls_extras = }, {id(car1.cls_extras) = }\")\n", @@ -298,7 +305,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 2, "id": "391e816e-c53b-454b-9e9f-3587234f1fea", "metadata": {}, "outputs": [ @@ -388,7 +395,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 3, "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c", "metadata": {}, "outputs": [ @@ -470,7 +477,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 4, "id": "71a90ec6-3cc0-441e-a866-c2c2b9984559", "metadata": {}, "outputs": [ @@ -478,9 +485,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "my_first_vector = Vector(start=, end=)\n", - "my_first_vector = Vector(start=, end=)\n", - "other_vector = Vector(start=, end=)\n", + "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=9, y=12))\n", + "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n", + "other_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n", "other_vector.length = Decimal('16.97056274847714058562026469')\n", "True\n", "True\n", @@ -502,7 +509,7 @@ " self._x = x\n", " self._y = y\n", "\n", - " def __bool__(self):\n", + " def __bool__(self) -> bool:\n", " \"\"\"\n", " Called to implement truth value testing and the built-in operation\n", " bool(); should return False or True. When this method is not defined,\n", @@ -529,7 +536,7 @@ "\n", " # \"fix\" self.__y -> self._y\n", " def __repr__(self) -> str:\n", - " return f\"\"\n", + " return f\"Point(x={self._x!r}, y={self._y!r})\"\n", "\n", " def __str__(self) -> str:\n", " return f\"{self._x}:{self._y}\"\n", @@ -588,7 +595,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 5, "id": "a4d2735d-d167-4f43-ad55-cb3d13ece2dc", "metadata": {}, "outputs": [ @@ -596,7 +603,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "list(vector) = [, ]\n", + "list(vector) = [Point(x=1, y=1), Point(x=4, y=6)]\n", "1:1\n", "4:6\n", "Exhausted\n" @@ -631,7 +638,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 6, "id": "a6ead5e6-e987-4bda-bf48-30f91877278d", "metadata": {}, "outputs": [ @@ -662,7 +669,7 @@ " protocol via __getitem__(), see this section in the language\n", " reference.\n", " \"\"\"\n", - " # ont of the following two strategies may be employed:\n", + " # one of the following two strategies may be employed:\n", " # return point is self._start or point is self._end\n", " # return point == self._start or point == self._end\n", " return point == self._start or point == self._end\n", @@ -690,7 +697,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 7, "id": "11f6a3fb-64d7-40a9-a130-27548ec4b802", "metadata": {}, "outputs": [ @@ -699,9 +706,9 @@ "output_type": "stream", "text": [ "__mul__ called\n", - "vector * 3 = Vector(start=, end=)\n", + "vector * 3 = Vector(start=Point(x=2, y=2), end=Point(x=12, y=18))\n", "__rmul__ called\n", - "3 * vector = Vector(start=, end=)\n" + "3 * vector = Vector(start=Point(x=2, y=2), end=Point(x=12, y=18))\n" ] } ], @@ -727,6 +734,8 @@ " return self._start\n", " if key in (\"end\", 1):\n", " return self._end\n", + " if isinstance(key, int):\n", + " raise IndexError\n", " raise KeyError\n", "\n", " def __mul__(self, other):\n", @@ -757,7 +766,7 @@ " returns NotImplemented.\n", " \"\"\"\n", " print(\"__rmul__ called\")\n", - " return Vector(self._start, Point(self._end.x * other, self._end.y * other))\n", + " return Vector(self._start, Point(self._end.x * other, self._end.y * other)) # self.__class__ may be used instead of Vector???\n", "\n", " # __rmul__ = __mul__\n", "\n", @@ -768,7 +777,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 8, "id": "c345a69f-02da-40e7-bb37-c0511b6af096", "metadata": {}, "outputs": [ @@ -777,7 +786,7 @@ "output_type": "stream", "text": [ "9\n", - "Vector.from_str('1:1:5:6') = Vector(start=, end=)\n" + "Vector.from_str('1:1:5:6') = Vector(start=Point(x=1, y=1), end=Point(x=5, y=6))\n" ] } ], @@ -789,6 +798,8 @@ " @staticmethod\n", " def get_manhattan_distance(point1: Point, point2: Point) -> int:\n", " \"\"\"Returns the Manhattan distance of two points\"\"\"\n", + " # usually this will be a regular method of type:\n", + " # def get_manhattan_distance(self, other: Point) -> int:\n", " return abs(point1.x - point2.x) + abs(point1.y - point2.y)\n", "\n", "\n", @@ -859,7 +870,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 9, "id": "44d47e1c-1a06-4577-8db6-6ec78ce5cef8", "metadata": {}, "outputs": [ @@ -1033,7 +1044,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 10, "id": "e6076925-75f0-456c-aed5-7db0a24a67a1", "metadata": {}, "outputs": [ @@ -1144,7 +1155,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 11, "id": "cf79617a-95d2-48f2-be66-fa1fa34e4e04", "metadata": {}, "outputs": [ @@ -1223,7 +1234,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 12, "id": "95a1d0cc-0006-4ddc-b08d-d0b8b02acfba", "metadata": {}, "outputs": [ @@ -1289,7 +1300,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 13, "id": "38066107-0190-4383-ba14-a4e9cd454a9c", "metadata": {}, "outputs": [ -- cgit v1.3