|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "metadata": {}, |
| 6 | + "source": [ |
| 7 | + "# Polymorphism\n", |
| 8 | + "\n", |
| 9 | + "Another important goal of the object-oriented approach to programming is to provide flexibility of your code. This can be achived by Polymorphism, which entails that an entity is able to take multiple forms. In Python polymorphism allows us to create methods in a child class with the same name as a method in a parent class. This would mean that a method can serve one purpose in a parent class and different one in a child class.\n", |
| 10 | + "\n", |
| 11 | + "Child classes inherit all the methods of their parent classes, however, sometimes those methods need to be modified to fit the function of the child. This is achieved by reimplementing the parent methods in the child class.\n", |
| 12 | + "\n", |
| 13 | + "To better understand polymorphism, let's look at an example of a class that can be based on the Shuttle class and transitively on the Rocket class as well." |
| 14 | + ] |
| 15 | + }, |
| 16 | + { |
| 17 | + "cell_type": "markdown", |
| 18 | + "metadata": {}, |
| 19 | + "source": [ |
| 20 | + "## The ImprovedShuttle class\n", |
| 21 | + "\n", |
| 22 | + "Our Shuttle class already improves the basic Rocket class, however, the information we receive from the Rocket class such as `get_distance` is very limited. This is because we currently only get information about the absolute distance, but we do not know the direction, which we need to face to get to that place the fastest.\n", |
| 23 | + "\n", |
| 24 | + "Therefore, we will create an improved Shuttle, which will be based on the initial Shuttle and will provide better distance information such as angle in which we need to rotate. The formula used is based on taking arctangent of the 2-dimension distances and transforming from radians to degrees.\n", |
| 25 | + "\n", |
| 26 | + "Here is what the ImprovedShuttle class looks like:" |
| 27 | + ] |
| 28 | + }, |
| 29 | + { |
| 30 | + "cell_type": "code", |
| 31 | + "execution_count": 2, |
| 32 | + "metadata": {}, |
| 33 | + "outputs": [ |
| 34 | + { |
| 35 | + "name": "stdout", |
| 36 | + "output_type": "stream", |
| 37 | + "text": [ |
| 38 | + "The shuttles are 4.242641 units apart.\n", |
| 39 | + "The angle the initial shuttle needs to rotate in case it needs to go to the other shuttle is 45.00 degrees.\n" |
| 40 | + ] |
| 41 | + } |
| 42 | + ], |
| 43 | + "source": [ |
| 44 | + "from rocket import Shuttle\n", |
| 45 | + "\n", |
| 46 | + "from math import atan, pi, sqrt\n", |
| 47 | + "\n", |
| 48 | + "class ImprovedShuttle(Shuttle):\n", |
| 49 | + " # Improved Shuttle that provides better distance information\n", |
| 50 | + " # such as angle.\n", |
| 51 | + " \n", |
| 52 | + " def __init__(self, x=0, y=0, flights_completed=0):\n", |
| 53 | + " super().__init__(x, y)\n", |
| 54 | + " self.flights_completed = flights_completed\n", |
| 55 | + " \n", |
| 56 | + " def get_distance(self, other_rocket):\n", |
| 57 | + " # Calculates the distance from this rocket to another rocket,\n", |
| 58 | + " # the angle to rotate to face the other rocket,\n", |
| 59 | + " # and returns those values.\n", |
| 60 | + " distance = super().get_distance(other_rocket)\n", |
| 61 | + " angle = atan((other_rocket.y - self.y) / (other_rocket.x - self.x)) * (180 / pi)\n", |
| 62 | + " return distance, angle\n", |
| 63 | + " \n", |
| 64 | + "improvedShuttle = ImprovedShuttle(10,0,3)\n", |
| 65 | + "otherShuttle = ImprovedShuttle(13, 3)\n", |
| 66 | + "\n", |
| 67 | + "# Show the distance between them.\n", |
| 68 | + "distance, angle = improvedShuttle.get_distance(otherShuttle)\n", |
| 69 | + "print(f\"The shuttles are {distance:.6f} units apart.\")\n", |
| 70 | + "print(f\"The angle the initial shuttle needs to rotate in case it needs to go to the other shuttle is {angle:.2f} degrees.\")" |
| 71 | + ] |
| 72 | + }, |
| 73 | + { |
| 74 | + "cell_type": "markdown", |
| 75 | + "metadata": {}, |
| 76 | + "source": [ |
| 77 | + "As you can see in the example above, since ImprovedShuttle inherits Shuttle and Shuttle inherits Rocket, then transitively ImprovedShuttle is a child of Rocket class and has access to the parent `get_distance` method. It is possible to access that parent method by making a `super().get_distance()` call.\n", |
| 78 | + "\n", |
| 79 | + "As a result, class ImprovedShuttle has ***overridden*** Rocket's get_distance. This means that it has reimplemented the parent's method.\n", |
| 80 | + "\n", |
| 81 | + "It is important to mention that it is not necessary to override (reimplement) every method in the parent class when using inheritance, but if needed, it is possible. \n", |
| 82 | + "\n", |
| 83 | + ":::{note}\n", |
| 84 | + "ImprovedShuttle's get_distance() now returns two outputs, while the parent class only returns one. Imagine you are looping a list containing a mix of Rockets and ImprovedShuttles to store their distance in an array (with as many elements as the length of the lists); this difference in the output may require some extra lines of code to handle potential problems.\n", |
| 85 | + ":::" |
| 86 | + ] |
| 87 | + } |
| 88 | + ], |
| 89 | + "metadata": { |
| 90 | + "kernelspec": { |
| 91 | + "display_name": "Python 3", |
| 92 | + "language": "python", |
| 93 | + "name": "python3" |
| 94 | + }, |
| 95 | + "language_info": { |
| 96 | + "codemirror_mode": { |
| 97 | + "name": "ipython", |
| 98 | + "version": 3 |
| 99 | + }, |
| 100 | + "file_extension": ".py", |
| 101 | + "mimetype": "text/x-python", |
| 102 | + "name": "python", |
| 103 | + "nbconvert_exporter": "python", |
| 104 | + "pygments_lexer": "ipython3", |
| 105 | + "version": "3.12.0" |
| 106 | + } |
| 107 | + }, |
| 108 | + "nbformat": 4, |
| 109 | + "nbformat_minor": 4 |
| 110 | +} |
0 commit comments