summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimeon Simeonov2022-12-15 22:21:22 +0100
committerSimeon Simeonov2022-12-15 22:21:22 +0100
commita767bdb2e9939f92fb048994fb77007fa0d350bd (patch)
treeb318da3fc84d51ceb0600bd9d288d22da4f0857e
parent6a6d09c488826c5d8e618f3d0a5db9997914b5f5 (diff)
Update notebooks/python/python_oo.ipynb
-rw-r--r--notebooks/python/python_oo.ipynb195
1 files changed, 131 insertions, 64 deletions
diff --git a/notebooks/python/python_oo.ipynb b/notebooks/python/python_oo.ipynb
index 7147a87..ff48ca0 100644
--- a/notebooks/python/python_oo.ipynb
+++ b/notebooks/python/python_oo.ipynb
@@ -42,7 +42,7 @@
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\"**\n",
44 "\n", 44 "\n",
45 "- Control flow: if / for / while / try, iterators, \"tactical programming\" tips\n", 45 "- Control flow: if / for / while / try, use of iterators, \"tactical programming\" tips\n",
46 "\n", 46 "\n",
47 "- A brief tour through Python's standard library\n", 47 "- A brief tour through Python's standard library\n",
48 "\n", 48 "\n",
@@ -120,6 +120,10 @@
120 "\n", 120 "\n",
121 "## SOLID\n", 121 "## SOLID\n",
122 "\n", 122 "\n",
123 "Robert C. Martin - 2000 paper \"Design Principles and Design Patterns\" discussing software rot.\n",
124 "\n",
125 "The *SOLID* acronym was introduced later, around 2004, by Michael Feathers.\n",
126 "\n",
123 "- **S**ingle responsibility principle - a class should have only a single responsibility or a single job or a single purpose. We should strictly avoid using generalized classes where the entire implementation is given in the same class. It also states that the responsibility should be entirely encapsulated by the class, module, or function.\n", 127 "- **S**ingle responsibility principle - a class should have only a single responsibility or a single job or a single purpose. We should strictly avoid using generalized classes where the entire implementation is given in the same class. It also states that the responsibility should be entirely encapsulated by the class, module, or function.\n",
124 "\n", 128 "\n",
125 "- **O**pen/closed principle - entities like classes, modules, functions, etc. should be open for extension and the classes should be closed for modification. This means that we should be able to extend a class behavior, without modifying it.\n", 129 "- **O**pen/closed principle - entities like classes, modules, functions, etc. should be open for extension and the classes should be closed for modification. This means that we should be able to extend a class behavior, without modifying it.\n",
@@ -137,9 +141,7 @@
137 "\n", 141 "\n",
138 "- avoid global and non-deterministic behavior - \"we need to ensure that the global behavior of the variables and objects are minimized. This can be visualized with an example of creating an animal cheetah. The color of the animal doesn’t change after its creation. So, we need to ensure that the attribute is not global and is unreachable to make sure data clashes don’t occur. Therefore, the use of global variables or objects needs to be avoided. We can use the concept of encapsulation on the data members to solve this issue.\"\n", 142 "- avoid global and non-deterministic behavior - \"we need to ensure that the global behavior of the variables and objects are minimized. This can be visualized with an example of creating an animal cheetah. The color of the animal doesn’t change after its creation. So, we need to ensure that the attribute is not global and is unreachable to make sure data clashes don’t occur. Therefore, the use of global variables or objects needs to be avoided. We can use the concept of encapsulation on the data members to solve this issue.\"\n",
139 "\n", 143 "\n",
140 "- reducing conditional statements - The usage of conditional statements must be reduced as much as possible. Using too many conditional statements in the program increases the complexity as well as the code cannot be reused. Instead, we can make use of interfaces and abstract classes and implement the conditional logic in different methods which can be reused and also, the single responsibility of the methods and classes is maintained. Wherever we need to reuse the same conditioning, we simply call the method where it is implemented instead of writing the code again.\n", 144 "- reducing conditional statements - The usage of conditional statements must be reduced as much as possible. Using too many conditional statements in the program increases the complexity as well as the code cannot be reused. Instead, we can make use of interfaces and abstract classes and implement the conditional logic in different methods which can be reused and also, the single responsibility of the methods and classes is maintained. Wherever we need to reuse the same conditioning, we simply call the method where it is implemented instead of writing the code again."
141 "\n",
142 "- autonomy principle - "
143 ] 145 ]
144 }, 146 },
145 { 147 {
@@ -183,6 +185,8 @@
183 "\n", 185 "\n",
184 "- `dir(obj)` - returns a list of valid attributes for that object\n", 186 "- `dir(obj)` - returns a list of valid attributes for that object\n",
185 "\n", 187 "\n",
188 "- `hasattr(object, name)` - returns `True` if *object* contains attribute *name*\n",
189 "\n",
186 "- `help(object)` - invokes the built-in help system. This function is intended for interactive use.\n", 190 "- `help(object)` - invokes the built-in help system. This function is intended for interactive use.\n",
187 "\n", 191 "\n",
188 "- `id(object)` - returns the \"identity\" (unique number) of the *object*\n", 192 "- `id(object)` - returns the \"identity\" (unique number) of the *object*\n",
@@ -193,44 +197,48 @@
193 "\n", 197 "\n",
194 "- `super([type[, object-or-type]])` - returns a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. **More on that later**.\n", 198 "- `super([type[, object-or-type]])` - returns a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. **More on that later**.\n",
195 "\n", 199 "\n",
196 "- `type(object)` - returns the type of an object. Useful for debugging / analysis." 200 "- `type(object)` - returns the type of an object. Useful for debugging / analysis.\n"
197 ] 201 ]
198 }, 202 },
199 { 203 {
200 "cell_type": "markdown", 204 "cell_type": "markdown",
201 "id": "d647b1ad-948d-495d-bb30-15761b806354", 205 "id": "3db6b54c-c65b-4ec8-b0d7-32123e806061",
202 "metadata": {}, 206 "metadata": {},
203 "source": [ 207 "source": [
204 "# Example1\n", 208 "# Example 1 - Creating instances of a class (objects)"
205 "\n",
206 "We will create and extend classes for representing points and vectors in 2D space"
207 ] 209 ]
208 }, 210 },
209 { 211 {
210 "cell_type": "code", 212 "cell_type": "code",
211 "execution_count": 1, 213 "execution_count": 40,
212 "id": "391e816e-c53b-454b-9e9f-3587234f1fea", 214 "id": "a9c30a5d-aa86-45ab-b897-f051df80f1d8",
213 "metadata": {}, 215 "metadata": {},
214 "outputs": [ 216 "outputs": [
215 { 217 {
216 "name": "stdout", 218 "name": "stdout",
217 "output_type": "stream", 219 "output_type": "stream",
218 "text": [ 220 "text": [
219 "2:8\n", 221 "car1.get_obj_info_str() = \"I am <__main__.Car object at 0x7fdda86a51d0> with id 140589990040016 from <class '__main__.Car'> with id 93981278397392\"\n",
220 "<Point(x=2, y=8)>\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",
221 "my_first_point = 2:8\n", 223 "id(Car.cls_extras) = 140589990168000, id(Car.__init__) = 140589989979424\n",
222 "my_first_point = <Point(x=2, y=8)>\n", 224 "car1.model = 'BMW', car1.reg_nr = 'EC76183', car1.extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000, id(car1.__init__) = 140589990039168\n",
223 "2\n", 225 "car2.model = 'Scoda', car2.reg_nr = 'BD77655', car2.extras = ['GPSnav'], id(car2.cls_extras) = 140589990168000, id(car2.__init__) = 140589990039808\n",
224 "2\n", 226 "car1.cls_extras = ['GPSnav', 'Sound system'], id(car1.cls_extras) = 140589990168000\n",
225 "8\n" 227 "car2.cls_extras = ['GPSnav', 'Sound system'], id(car2.cls_extras) = 140589990168000\n",
228 "True\n",
229 "hasattr(car1, 'import_tax_paid') = True\n",
230 "hasattr(car2, 'import_tax_paid') = False\n",
231 "id(car1.__class__) = 93981278397392, id(car2.__class__) = 93981278397392, id(Car) = 93981278397392\n"
226 ] 232 ]
227 } 233 }
228 ], 234 ],
229 "source": [ 235 "source": [
230 "class Point:\n", 236 "class Car: # base class that inherits only from 'object' (class Car(object): )\n",
231 " \"\"\"Basic class for representing points in 2D space\"\"\"\n",
232 "\n", 237 "\n",
233 " def __init__(self, x: int, y: int):\n", 238 " cls_extras = [] # class attribute - shared by all instances\n",
239 " # cls_extras: list = [] is also possible\n",
240 "\n",
241 " def __init__(self, model: str, reg_nr: str, extras: list):\n",
234 " \"\"\"\n", 242 " \"\"\"\n",
235 " Called after the instance has been created (by __new__()), but before\n", 243 " Called after the instance has been created (by __new__()), but before\n",
236 " it is returned to the caller. The arguments are those passed to the\n", 244 " it is returned to the caller. The arguments are those passed to the\n",
@@ -241,6 +249,78 @@
241 " initialization of the base class part of the instance;\n", 249 " initialization of the base class part of the instance;\n",
242 " for example: super().__init__([args...]).\n", 250 " for example: super().__init__([args...]).\n",
243 " \"\"\"\n", 251 " \"\"\"\n",
252 " self.model = model # instance attribute - unique for a particular instance (object)\n",
253 " self.reg_nr = reg_nr\n",
254 " self.extras = extras\n",
255 "\n",
256 " # self.cls_extras = extras # will create a *NEW instance attribute* called 'cls_extras'\n",
257 " \n",
258 " def get_obj_info_str(self): # regular method that becomes instance attribute\n",
259 " return f\"I am {self} with id {id(self)} from {self.__class__} with id {id(self.__class__)}\"\n",
260 "\n",
261 "car1 = Car(\"BMW\", \"EC76183\", [\"GPSnav\", \"Sound system\"])\n",
262 "car2 = Car(\"Scoda\", \"BD77655\", [\"GPSnav\"])\n",
263 "\n",
264 "print(f\"{car1.get_obj_info_str() = }\")\n",
265 "print(f\"{car2.get_obj_info_str() = }\")\n",
266 "\n",
267 "# default behavior for `object.attr`:\n",
268 "# getter:\n",
269 "# - checks if 'attr' is an instance attribute\n",
270 "# - checks if 'attr' is a class attribute\n",
271 "# - raises AttributeError\n",
272 "# 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",
275 "print(f\"{car2.model = }, {car2.reg_nr = }, {car2.extras = }, {id(car2.cls_extras) = }, {id(car2.__init__) = }\")\n",
276 "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",
278 "print(f\"{car1.cls_extras = }, {id(car1.cls_extras) = }\")\n",
279 "print(f\"{car2.cls_extras = }, {id(car2.cls_extras) = }\")\n",
280 "\n",
281 "# creating new instance attributes that have no connection to the corresponding class (type) is possible:\n",
282 "car1.import_tax_paid = True # 'import_tax_paid' will only be present in car1\n",
283 "print(car1.import_tax_paid)\n",
284 "print(f\"{hasattr(car1, 'import_tax_paid') = }\") # Out: True\n",
285 "print(f\"{hasattr(car2, 'import_tax_paid') = }\") # Out: False\n",
286 "\n",
287 "# .__class__ instance attribute pointing to its class (type) will be created\n",
288 "print(f\"{id(car1.__class__) = }, {id(car2.__class__) = }, {id(Car) = }\")"
289 ]
290 },
291 {
292 "cell_type": "markdown",
293 "id": "d647b1ad-948d-495d-bb30-15761b806354",
294 "metadata": {},
295 "source": [
296 "# Example 2 - Creating and extending classes for representing points and vectors in 2D space"
297 ]
298 },
299 {
300 "cell_type": "code",
301 "execution_count": 41,
302 "id": "391e816e-c53b-454b-9e9f-3587234f1fea",
303 "metadata": {},
304 "outputs": [
305 {
306 "name": "stdout",
307 "output_type": "stream",
308 "text": [
309 "2:8\n",
310 "Point(x=2, y=8)\n",
311 "my_first_point = 2:8\n",
312 "my_first_point = Point(x=2, y=8)\n",
313 "2\n",
314 "2\n",
315 "8\n"
316 ]
317 }
318 ],
319 "source": [
320 "class Point:\n",
321 " \"\"\"Basic class for representing points in 2D space\"\"\"\n",
322 "\n",
323 " def __init__(self, x: int, y: int):\n",
244 " # defines instance attributes that will \"live\" as long as\n", 324 " # defines instance attributes that will \"live\" as long as\n",
245 " # the object / instance \"lives\" \n", 325 " # the object / instance \"lives\" \n",
246 " self._x = x # _ indicates \"protected\" attribute\n", 326 " self._x = x # _ indicates \"protected\" attribute\n",
@@ -260,7 +340,7 @@
260 " that class is required. This is typically used for debugging, so it is\n", 340 " that class is required. This is typically used for debugging, so it is\n",
261 " important that the representation is information-rich and unambiguous.\n", 341 " important that the representation is information-rich and unambiguous.\n",
262 " \"\"\"\n", 342 " \"\"\"\n",
263 " return f\"<Point(x={self._x!r}, y={self.__y!r})>\"\n", 343 " return f\"Point(x={self._x!r}, y={self.__y!r})\"\n",
264 "\n", 344 "\n",
265 " def __str__(self) -> str:\n", 345 " def __str__(self) -> str:\n",
266 " \"\"\"\n", 346 " \"\"\"\n",
@@ -308,7 +388,7 @@
308 }, 388 },
309 { 389 {
310 "cell_type": "code", 390 "cell_type": "code",
311 "execution_count": 2, 391 "execution_count": 42,
312 "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c", 392 "id": "e82feefb-025d-4cbb-a8ac-ddc3cc01269c",
313 "metadata": {}, 393 "metadata": {},
314 "outputs": [ 394 "outputs": [
@@ -316,9 +396,9 @@
316 "name": "stdout", 396 "name": "stdout",
317 "output_type": "stream", 397 "output_type": "stream",
318 "text": [ 398 "text": [
319 "my_first_vector = <Vector (start=<Point(x=0, y=0)>, end=<Point(x=9, y=12)>>\n", 399 "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=9, y=12))\n",
320 "my_first_vector = <Vector (start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>>\n", 400 "my_first_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n",
321 "other_vector = <Vector (start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>>\n", 401 "other_vector = Vector(start=Point(x=0, y=0), end=Point(x=12, y=12))\n",
322 "other_vector.length = Decimal('16.97056274847714058562026469')\n", 402 "other_vector.length = Decimal('16.97056274847714058562026469')\n",
323 "False\n", 403 "False\n",
324 "False\n", 404 "False\n",
@@ -337,10 +417,9 @@
337 " self._end = end\n", 417 " self._end = end\n",
338 "\n", 418 "\n",
339 " def __repr__(self) -> str:\n", 419 " def __repr__(self) -> str:\n",
340 " return f\"<Vector (start={self._start!r}, end={self._end!r}>\"\n", 420 " return f\"Vector(start={self._start!r}, end={self._end!r})\"\n",
341 "\n", 421 "\n",
342 " def __str__(self) -> str:\n", 422 " def __str__(self) -> str:\n",
343 " print('str-called')\n",
344 " return f\"{self._start} -> {self._end}\"\n", 423 " return f\"{self._start} -> {self._end}\"\n",
345 "\n", 424 "\n",
346 " @property\n", 425 " @property\n",
@@ -354,7 +433,7 @@
354 " self._end = value\n", 433 " self._end = value\n",
355 "\n", 434 "\n",
356 " @property\n", 435 " @property\n",
357 " def length(self) -> decimal.Decimal:\n", 436 " def length(self) -> decimal.Decimal: # could also be a method f.i. def get_length(self) -> decimal.Decimal:\n",
358 " \"\"\"length of a Vector property\"\"\"\n", 437 " \"\"\"length of a Vector property\"\"\"\n",
359 " # length: sqrt(a^2 + b^2)\n", 438 " # length: sqrt(a^2 + b^2)\n",
360 " return (\n", 439 " return (\n",
@@ -391,7 +470,7 @@
391 }, 470 },
392 { 471 {
393 "cell_type": "code", 472 "cell_type": "code",
394 "execution_count": 3, 473 "execution_count": 43,
395 "id": "71a90ec6-3cc0-441e-a866-c2c2b9984559", 474 "id": "71a90ec6-3cc0-441e-a866-c2c2b9984559",
396 "metadata": {}, 475 "metadata": {},
397 "outputs": [ 476 "outputs": [
@@ -399,9 +478,9 @@
399 "name": "stdout", 478 "name": "stdout",
400 "output_type": "stream", 479 "output_type": "stream",
401 "text": [ 480 "text": [
402 "my_first_vector = <Vector (start=<Point(x=0, y=0)>, end=<Point(x=9, y=12)>>\n", 481 "my_first_vector = Vector(start=<Point(x=0, y=0)>, end=<Point(x=9, y=12)>)\n",
403 "my_first_vector = <Vector (start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>>\n", 482 "my_first_vector = Vector(start=<Point(x=0, y=0)>, end=<Point(x=12, y=12)>)\n",
404 "other_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",
405 "other_vector.length = Decimal('16.97056274847714058562026469')\n", 484 "other_vector.length = Decimal('16.97056274847714058562026469')\n",
406 "True\n", 485 "True\n",
407 "True\n", 486 "True\n",
@@ -440,7 +519,11 @@
440 " A rich comparison method may return the singleton NotImplemented if it\n", 519 " A rich comparison method may return the singleton NotImplemented if it\n",
441 " does not implement the operation for a given pair of arguments.\n", 520 " does not implement the operation for a given pair of arguments.\n",
442 " By convention, False and True are returned for a successful comparison.\n", 521 " By convention, False and True are returned for a successful comparison.\n",
443 " However, these methods can return any value\n", 522 " However, these methods can return any value.\n",
523 " \n",
524 " If the operands are of different types, and right operand’s type is a direct or indirect\n",
525 " subclass of the left operand’s type, the reflected method of the right operand has priority,\n",
526 " otherwise the left operand’s method has priority. Virtual subclassing is not considered.\n",
444 " \"\"\"\n", 527 " \"\"\"\n",
445 " return self._x == other.x and self._y == other.y\n", 528 " return self._x == other.x and self._y == other.y\n",
446 "\n", 529 "\n",
@@ -505,7 +588,7 @@
505 }, 588 },
506 { 589 {
507 "cell_type": "code", 590 "cell_type": "code",
508 "execution_count": 4, 591 "execution_count": 44,
509 "id": "a4d2735d-d167-4f43-ad55-cb3d13ece2dc", 592 "id": "a4d2735d-d167-4f43-ad55-cb3d13ece2dc",
510 "metadata": {}, 593 "metadata": {},
511 "outputs": [ 594 "outputs": [
@@ -548,7 +631,7 @@
548 }, 631 },
549 { 632 {
550 "cell_type": "code", 633 "cell_type": "code",
551 "execution_count": 5, 634 "execution_count": 45,
552 "id": "a6ead5e6-e987-4bda-bf48-30f91877278d", 635 "id": "a6ead5e6-e987-4bda-bf48-30f91877278d",
553 "metadata": {}, 636 "metadata": {},
554 "outputs": [ 637 "outputs": [
@@ -607,7 +690,7 @@
607 }, 690 },
608 { 691 {
609 "cell_type": "code", 692 "cell_type": "code",
610 "execution_count": 6, 693 "execution_count": 46,
611 "id": "11f6a3fb-64d7-40a9-a130-27548ec4b802", 694 "id": "11f6a3fb-64d7-40a9-a130-27548ec4b802",
612 "metadata": {}, 695 "metadata": {},
613 "outputs": [ 696 "outputs": [
@@ -616,9 +699,9 @@
616 "output_type": "stream", 699 "output_type": "stream",
617 "text": [ 700 "text": [
618 "__mul__ called\n", 701 "__mul__ called\n",
619 "vector * 3 = <Vector (start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>>\n", 702 "vector * 3 = Vector(start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>)\n",
620 "__rmul__ called\n", 703 "__rmul__ called\n",
621 "3 * vector = <Vector (start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>>\n" 704 "3 * vector = Vector(start=<Point(x=2, y=2)>, end=<Point(x=12, y=18)>)\n"
622 ] 705 ]
623 } 706 }
624 ], 707 ],
@@ -685,7 +768,7 @@
685 }, 768 },
686 { 769 {
687 "cell_type": "code", 770 "cell_type": "code",
688 "execution_count": 7, 771 "execution_count": 47,
689 "id": "c345a69f-02da-40e7-bb37-c0511b6af096", 772 "id": "c345a69f-02da-40e7-bb37-c0511b6af096",
690 "metadata": {}, 773 "metadata": {},
691 "outputs": [ 774 "outputs": [
@@ -694,7 +777,7 @@
694 "output_type": "stream", 777 "output_type": "stream",
695 "text": [ 778 "text": [
696 "9\n", 779 "9\n",
697 "Vector.from_str('1:1:5:6') = <Vector (start=<Point(x=1, y=1)>, end=<Point(x=5, y=6)>>\n" 780 "Vector.from_str('1:1:5:6') = Vector(start=<Point(x=1, y=1)>, end=<Point(x=5, y=6)>)\n"
698 ] 781 ]
699 } 782 }
700 ], 783 ],
@@ -776,7 +859,7 @@
776 }, 859 },
777 { 860 {
778 "cell_type": "code", 861 "cell_type": "code",
779 "execution_count": 8, 862 "execution_count": 48,
780 "id": "44d47e1c-1a06-4577-8db6-6ec78ce5cef8", 863 "id": "44d47e1c-1a06-4577-8db6-6ec78ce5cef8",
781 "metadata": {}, 864 "metadata": {},
782 "outputs": [ 865 "outputs": [
@@ -950,7 +1033,7 @@
950 }, 1033 },
951 { 1034 {
952 "cell_type": "code", 1035 "cell_type": "code",
953 "execution_count": 9, 1036 "execution_count": 49,
954 "id": "e6076925-75f0-456c-aed5-7db0a24a67a1", 1037 "id": "e6076925-75f0-456c-aed5-7db0a24a67a1",
955 "metadata": {}, 1038 "metadata": {},
956 "outputs": [ 1039 "outputs": [
@@ -1061,7 +1144,7 @@
1061 }, 1144 },
1062 { 1145 {
1063 "cell_type": "code", 1146 "cell_type": "code",
1064 "execution_count": 13, 1147 "execution_count": 50,
1065 "id": "cf79617a-95d2-48f2-be66-fa1fa34e4e04", 1148 "id": "cf79617a-95d2-48f2-be66-fa1fa34e4e04",
1066 "metadata": {}, 1149 "metadata": {},
1067 "outputs": [ 1150 "outputs": [
@@ -1140,7 +1223,7 @@
1140 }, 1223 },
1141 { 1224 {
1142 "cell_type": "code", 1225 "cell_type": "code",
1143 "execution_count": 11, 1226 "execution_count": 51,
1144 "id": "95a1d0cc-0006-4ddc-b08d-d0b8b02acfba", 1227 "id": "95a1d0cc-0006-4ddc-b08d-d0b8b02acfba",
1145 "metadata": {}, 1228 "metadata": {},
1146 "outputs": [ 1229 "outputs": [
@@ -1206,7 +1289,7 @@
1206 }, 1289 },
1207 { 1290 {
1208 "cell_type": "code", 1291 "cell_type": "code",
1209 "execution_count": 12, 1292 "execution_count": 52,
1210 "id": "38066107-0190-4383-ba14-a4e9cd454a9c", 1293 "id": "38066107-0190-4383-ba14-a4e9cd454a9c",
1211 "metadata": {}, 1294 "metadata": {},
1212 "outputs": [ 1295 "outputs": [
@@ -1216,23 +1299,7 @@
1216 "text": [ 1299 "text": [
1217 "Using mock data\n", 1300 "Using mock data\n",
1218 "Extracting production plans from data\n", 1301 "Extracting production plans from data\n",
1219 "some magic is happening here...\n" 1302 "some magic is happening here...\n",
1220 ]
1221 },
1222 {
1223 "data": {
1224 "text/plain": [
1225 "'{}'"
1226 ]
1227 },
1228 "execution_count": 12,
1229 "metadata": {},
1230 "output_type": "execute_result"
1231 },
1232 {
1233 "name": "stdout",
1234 "output_type": "stream",
1235 "text": [
1236 "(<class '__main__.MockedButStillCoolTSPreprocessor'>, <class '__main__.CoolTSPreprocessor'>, <class '__main__.MockConnectionManager'>, <class '__main__.ConnectionManager'>, <class 'object'>)\n" 1303 "(<class '__main__.MockedButStillCoolTSPreprocessor'>, <class '__main__.CoolTSPreprocessor'>, <class '__main__.MockConnectionManager'>, <class '__main__.ConnectionManager'>, <class 'object'>)\n"
1237 ] 1304 ]
1238 } 1305 }
@@ -1291,7 +1358,7 @@
1291 "name": "python", 1358 "name": "python",
1292 "nbconvert_exporter": "python", 1359 "nbconvert_exporter": "python",
1293 "pygments_lexer": "ipython3", 1360 "pygments_lexer": "ipython3",
1294 "version": "3.10.8" 1361 "version": "3.11.1"
1295 } 1362 }
1296 }, 1363 },
1297 "nbformat": 4, 1364 "nbformat": 4,