{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# HyperLearning AI - Introduction to Python\n", "An introductory course to the Python 3 programming language, with a curriculum aligned to the Certified Associate in Python Programming (PCAP) examination syllabus (PCAP-31-02).
\n", "https://knowledgebase.hyperlearning.ai/courses/introduction-to-python\n", "\n", "\n", "## 08. Classes and Objects Part 1\n", "https://knowledgebase.hyperlearning.ai/en/courses/introduction-to-python/modules/8/classes-and-objects-part-1\n", "\n", "In this module we will introduce the object oriented programming (OOP) paradigm - a means to model the world and our software applications as objects that interact with each other. Supported by hands-on examples in Python, we will explore the fundamental concepts in object oriented programming, including:\n", "\n", "* **Classes** - classes, superclasses, subclasses, inheritance, and creating objects\n", "* **Class Attributes** - class variables, instance variables, managing attributes and explicit constructor invocation\n", "* **Class Methods** - defining and using class methods, the self parameter, the init method and the str method\n", "* **Inheritance** - inheritance, overriding, single inheritance and multiple inheritance\n", "* **Constructors** - writing and using constructors\n", "* **Introspection** - dict, name, module and bases properties, and examining class structure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. Programming Paradigms\n", "#### 1.1. Imperative Programming" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The sum of the numbers in [1, 2, 3, 4, 5] is: 15\n" ] } ], "source": [ "# Write a program using imperative programming to calculate the sum of a given list of numbers\n", "sum = 0\n", "my_numbers = [1, 2, 3, 4, 5]\n", "for number in my_numbers:\n", " sum += number\n", "print(f'The sum of the numbers in {my_numbers} is: {sum}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 1.2. Functional Programming" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15\n", "15\n" ] } ], "source": [ "from functools import reduce\n", "\n", "# Write a program using functional programming to calculate the sum of a given list of numbers\n", "def add(x, y):\n", " return x + y\n", "sum = reduce(add, my_numbers)\n", "print(sum)\n", "\n", "# Write a program using functional programming and a lambda function to calculate the sum of a given list of numbers\n", "sum = reduce(lambda x, y: x + y, my_numbers)\n", "print(sum)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. OOP Fundamentals\n", "#### 2.2.1. Creating Objects" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Update sys.path so that it can find our example module\n", "import sys\n", "sys.path.append('examples/formulapy')" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# Import our example module containing our Car class definition\n", "from example import Car" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "__init__() missing 8 required positional arguments: 'number_doors', 'registration_number', 'make', 'model', 'year_manufactured', 'maximum_speed', 'acceleration_rate', and 'deceleration_rate'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Try to create a new car object without the required arguments\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mmy_car\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: __init__() missing 8 required positional arguments: 'number_doors', 'registration_number', 'make', 'model', 'year_manufactured', 'maximum_speed', 'acceleration_rate', and 'deceleration_rate'" ] } ], "source": [ "# Try to create a new car object without the required arguments\n", "my_car = Car()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Car{'number_doors': 0, 'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 200, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n", "Car{'number_doors': 0, 'registration_number': 'MON 888', 'make': 'Ferrari', 'model': 'SF1000', 'year_manufactured': 2020, 'maximum_speed': 200, 'acceleration_rate': 15, 'deceleration_rate': 60, 'mileage_miles': 0, 'speed_mph': 0}\n" ] } ], "source": [ "# Create a new car object\n", "mercedes_f1 = Car(number_doors = 0,\n", " registration_number = 'MERC 123',\n", " make = 'Mercedes',\n", " model = 'AMG F1 W10 EQ Power+',\n", " year_manufactured = 2019,\n", " maximum_speed = 200,\n", " acceleration_rate = 20,\n", " deceleration_rate = 50)\n", "\n", "# Print the type of object that this is i.e. the class that was used to instantiate this object\n", "print(type(mercedes_f1))\n", "\n", "# Print a string representation of the car object\n", "print(mercedes_f1)\n", "\n", "# Create another new car object\n", "ferrari_f1 = Car(number_doors = 0,\n", " registration_number = 'MON 888',\n", " make = 'Ferrari',\n", " model = 'SF1000',\n", " year_manufactured = 2020,\n", " maximum_speed = 200,\n", " acceleration_rate = 15,\n", " deceleration_rate = 60)\n", "\n", "# Print a string representation of the car object\n", "print(ferrari_f1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.2. Accessing Attributes" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "200\n", "MON 888\n" ] } ], "source": [ "# Access and display the maximum speed of the Mercedes car object\n", "print(mercedes_f1.maximum_speed)\n", "\n", "# Access and display the registration number of the Ferrari car object\n", "print(ferrari_f1.registration_number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.3. Modifying Attributes" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car{'number_doors': 0, 'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n", "Car{'number_doors': 0, 'registration_number': 'SCUD 888', 'make': 'Ferrari', 'model': 'SF1000', 'year_manufactured': 2020, 'maximum_speed': 200, 'acceleration_rate': 15, 'deceleration_rate': 60, 'mileage_miles': 0, 'speed_mph': 0}\n" ] } ], "source": [ "# Modify the maximum speed of the Mercedes car object\n", "mercedes_f1.maximum_speed = 220\n", "print(mercedes_f1)\n", "\n", "# Modify the registration number of the Ferrari car object\n", "ferrari_f1.registration_number = 'SCUD 888'\n", "print(ferrari_f1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.4. Deleting Attributes" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car{'number_doors': 0, 'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n", "0\n", "Car{'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n" ] }, { "ename": "AttributeError", "evalue": "'Car' object has no attribute 'number_doors'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mmercedes_f1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnumber_doors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmercedes_f1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmercedes_f1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnumber_doors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Car' object has no attribute 'number_doors'" ] } ], "source": [ "# Delete the number of doors attribute belonging to the Mercedes car object\n", "print(mercedes_f1)\n", "print(mercedes_f1.number_doors)\n", "del mercedes_f1.number_doors\n", "print(mercedes_f1)\n", "print(mercedes_f1.number_doors)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.5. Deleting Objects" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car{'number_doors': 0, 'registration_number': 'RB 999', 'make': 'Red Bull', 'model': 'RB9', 'year_manufactured': 2013, 'maximum_speed': 210, 'acceleration_rate': 18, 'deceleration_rate': 60, 'mileage_miles': 0, 'speed_mph': 0}\n" ] } ], "source": [ "# Create a new car object\n", "redbull_f1 = Car(number_doors = 0,\n", " registration_number = 'RB 999',\n", " make = 'Red Bull',\n", " model = 'RB9',\n", " year_manufactured = 2013,\n", " maximum_speed = 210,\n", " acceleration_rate = 18,\n", " deceleration_rate = 60)\n", "\n", "# Print a string representation of the car object\n", "print(redbull_f1)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'redbull_f1' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# Try to print a string representation of the deleted car object\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mredbull_f1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'redbull_f1' is not defined" ] } ], "source": [ "# Delete the previously created car object\n", "del redbull_f1\n", "\n", "# Try to print a string representation of the deleted car object\n", "print(redbull_f1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.6. Introspection" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n" ] } ], "source": [ "# Access an object's attribute references\n", "print(mercedes_f1.__dict__)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car\n", "\n", "Car\n" ] } ], "source": [ "# Access a class's name\n", "print(Car.__name__)\n", "\n", "# Access an object's class name (or type name) from which it was instantiated\n", "print(mercedes_f1.__class__)\n", "print(mercedes_f1.__class__.__name__)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "example\n", "example\n" ] } ], "source": [ "# Access the name of the module that a class was defined in\n", "print(Car.__module__)\n", "print(mercedes_f1.__class__.__module__)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(,)\n", "(,)\n" ] } ], "source": [ "# Access a class's base classes\n", "print(Car.__bases__)\n", "print(mercedes_f1.__class__.__bases__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.7. Adding Attributes" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car{'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0}\n", "Car{'registration_number': 'MERC 123', 'make': 'Mercedes', 'model': 'AMG F1 W10 EQ Power+', 'year_manufactured': 2019, 'maximum_speed': 220, 'acceleration_rate': 20, 'deceleration_rate': 50, 'mileage_miles': 0, 'speed_mph': 0, 'height_mm': 950, 'width_mm': 2000, 'weight_kg': 743, 'power_kw': 750}\n" ] } ], "source": [ "# Add a completely new attribute to one of our car objects that was not defined in the Car class definition\n", "print(mercedes_f1)\n", "setattr(mercedes_f1, 'height_mm', 950)\n", "setattr(mercedes_f1, 'width_mm', 2000)\n", "setattr(mercedes_f1, 'weight_kg', 743)\n", "setattr(mercedes_f1, 'power_kw', 750)\n", "print(mercedes_f1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.8. Invoking Methods" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "23/08/2020 21:01:21: Ferrari SF1000 current speed: 0mph\n", "23/08/2020 21:01:22: Ferrari SF1000 current speed: 15mph\n", "23/08/2020 21:01:23: Ferrari SF1000 current speed: 30mph\n", "23/08/2020 21:01:24: Ferrari SF1000 current speed: 45mph\n", "23/08/2020 21:01:25: Ferrari SF1000 current speed: 60mph\n", "23/08/2020 21:01:26: Ferrari SF1000 current speed: 75mph\n", "23/08/2020 21:01:27: Ferrari SF1000 current speed: 90mph\n", "23/08/2020 21:01:28: Ferrari SF1000 current speed: 105mph\n", "23/08/2020 21:01:29: Ferrari SF1000 current speed: 120mph\n", "23/08/2020 21:01:30: Ferrari SF1000 current speed: 135mph\n", "23/08/2020 21:01:31: Ferrari SF1000 current speed: 150mph\n", "23/08/2020 21:01:32: Ferrari SF1000 current speed: 165mph\n", "23/08/2020 21:01:33: Ferrari SF1000 current speed: 180mph\n", "23/08/2020 21:01:34: Ferrari SF1000 current speed: 195mph\n", "23/08/2020 21:01:35: Ferrari SF1000 current speed: 200mph\n" ] } ], "source": [ "# Invoke the Car.accelerate() method on an existing car object\n", "ferrari_f1.accelerate()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3. Inheritance\n", "#### 2.3.3. Super Function" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [], "source": [ "# Update sys.path so that it can find our formulapy module\n", "import sys\n", "sys.path.append('examples/formulapy')\n", "\n", "# Import our new vehicle domain data model module\n", "from model import Aircraft, Car, RoadVehicle, Vehicle" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Car{'number_engines': 1, 'engine_horsepower_kw': 673, 'chassis_height_mm': 1188, 'chassis_width_mm': 1946, 'chassis_depth_mm': 4588, 'make': 'McLaren', 'model': 'P1', 'year_manufactured': 2013, 'maximum_speed_mph': 217, 'acceleration_rate_mps': 20, 'deceleration_rate_mps': 50, 'mileage_miles': 0, 'speed_mph': 0, 'number_wheels': 4, 'registration_number': 'MCL P1', 'last_mot_date': '23/08/2020'}\n" ] } ], "source": [ "# Create a new car object\n", "mclaren_p1 = Car(number_engines = 1,\n", " engine_horsepower_kw = 673,\n", " chassis_height_mm = 1188,\n", " chassis_width_mm = 1946,\n", " chassis_depth_mm = 4588,\n", " make = 'McLaren',\n", " model = 'P1',\n", " year_manufactured = 2013,\n", " maximum_speed_mph = 217,\n", " acceleration_rate_mps = 20,\n", " deceleration_rate_mps = 50,\n", " registration_number = 'MCL P1')\n", "\n", "# Print a string representation of the car object\n", "print(mclaren_p1)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "217\n", "23/08/2020\n", "4\n" ] } ], "source": [ "# Access an attribute that is set in the Vehicle superclass\n", "print(mclaren_p1.maximum_speed_mph)\n", "\n", "# Access an attribute that is set in the RoadVehicle superclass\n", "print(mclaren_p1.last_mot_date)\n", "\n", "# Access an attribute that is set in the Car subclass\n", "print(mclaren_p1.number_wheels)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "23/08/2020 21:30:40: McLaren P1 current speed: 0mph\n", "23/08/2020 21:30:41: McLaren P1 current speed: 20mph\n", "23/08/2020 21:30:42: McLaren P1 current speed: 40mph\n", "23/08/2020 21:30:43: McLaren P1 current speed: 60mph\n", "23/08/2020 21:30:44: McLaren P1 current speed: 80mph\n", "23/08/2020 21:30:45: McLaren P1 current speed: 100mph\n", "23/08/2020 21:30:46: McLaren P1 current speed: 120mph\n", "23/08/2020 21:30:47: McLaren P1 current speed: 140mph\n", "23/08/2020 21:30:48: McLaren P1 current speed: 160mph\n", "23/08/2020 21:30:49: McLaren P1 current speed: 180mph\n", "23/08/2020 21:30:50: McLaren P1 current speed: 200mph\n", "23/08/2020 21:30:51: McLaren P1 current speed: 217mph\n", "None\n" ] } ], "source": [ "# Invoke a method that is defined in the Vehicle superclass\n", "print(mclaren_p1.accelerate())" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "23/08/2020 21:30:52: McLaren P1 current speed: 217mph\n", "23/08/2020 21:30:53: McLaren P1 current speed: 167mph\n", "23/08/2020 21:30:54: McLaren P1 current speed: 117mph\n", "23/08/2020 21:30:55: McLaren P1 current speed: 67mph\n", "23/08/2020 21:30:56: McLaren P1 current speed: 17mph\n", "23/08/2020 21:30:57: McLaren P1 current speed: 0mph\n", "None\n" ] } ], "source": [ "# Invoke a method that is defined in the Car class that itself invokes methods defined in the Vehicle superclass\n", "print(mclaren_p1.avoid_collision())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.4. Overriding Methods" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Aircraft{'number_engines': 4, 'engine_horsepower_kw': 670, 'chassis_height_mm': 24100, 'chassis_width_mm': 79800, 'chassis_depth_mm': 72700, 'make': 'Airbus', 'model': 'A380', 'year_manufactured': 2005, 'maximum_speed_mph': 736, 'acceleration_rate_mps': 30, 'deceleration_rate_mps': 30, 'mileage_miles': 0, 'speed_mph': 0, 'minimum_speed_mph': 150}\n" ] } ], "source": [ "# Create a new aircraft object\n", "airbus_a380 = Aircraft(number_engines = 4,\n", " engine_horsepower_kw = 670,\n", " chassis_height_mm = 24100,\n", " chassis_width_mm = 79800,\n", " chassis_depth_mm = 72700,\n", " make = 'Airbus',\n", " model = 'A380',\n", " year_manufactured = 2005,\n", " maximum_speed_mph = 736,\n", " acceleration_rate_mps = 30,\n", " deceleration_rate_mps = 30,\n", " minimum_speed_mph = 150)\n", "\n", "# Print a string representation of the aircraft object\n", "print(airbus_a380)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "24/08/2020 10:04:06: Airbus A380 current speed: 0mph\n", "24/08/2020 10:04:07: Airbus A380 current speed: 30mph\n", "24/08/2020 10:04:08: Airbus A380 current speed: 60mph\n", "24/08/2020 10:04:09: Airbus A380 current speed: 90mph\n", "24/08/2020 10:04:10: Airbus A380 current speed: 120mph\n", "24/08/2020 10:04:11: Airbus A380 current speed: 150mph\n", "24/08/2020 10:04:12: Airbus A380 current speed: 180mph\n", "24/08/2020 10:04:13: Airbus A380 current speed: 210mph\n", "24/08/2020 10:04:14: Airbus A380 current speed: 240mph\n", "24/08/2020 10:04:15: Airbus A380 current speed: 270mph\n", "24/08/2020 10:04:16: Airbus A380 current speed: 300mph\n", "24/08/2020 10:04:17: Airbus A380 current speed: 330mph\n", "24/08/2020 10:04:18: Airbus A380 current speed: 360mph\n", "24/08/2020 10:04:19: Airbus A380 current speed: 390mph\n", "24/08/2020 10:04:20: Airbus A380 current speed: 420mph\n", "24/08/2020 10:04:21: Airbus A380 current speed: 450mph\n", "24/08/2020 10:04:22: Airbus A380 current speed: 480mph\n", "24/08/2020 10:04:23: Airbus A380 current speed: 510mph\n", "24/08/2020 10:04:24: Airbus A380 current speed: 540mph\n", "24/08/2020 10:04:25: Airbus A380 current speed: 570mph\n", "24/08/2020 10:04:26: Airbus A380 current speed: 600mph\n", "24/08/2020 10:04:27: Airbus A380 current speed: 630mph\n", "24/08/2020 10:04:28: Airbus A380 current speed: 660mph\n", "24/08/2020 10:04:29: Airbus A380 current speed: 690mph\n", "24/08/2020 10:04:30: Airbus A380 current speed: 720mph\n", "24/08/2020 10:04:31: Airbus A380 current speed: 736mph\n", "None\n" ] } ], "source": [ "# Invoke a method that is defined in the Vehicle superclass\n", "print(airbus_a380.accelerate())" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "24/08/2020 10:04:53: Airbus A380 current speed: 736mph\n", "24/08/2020 10:04:54: Airbus A380 current speed: 706mph\n", "24/08/2020 10:04:55: Airbus A380 current speed: 676mph\n", "24/08/2020 10:04:56: Airbus A380 current speed: 646mph\n", "24/08/2020 10:04:57: Airbus A380 current speed: 616mph\n", "24/08/2020 10:04:58: Airbus A380 current speed: 586mph\n", "24/08/2020 10:04:59: Airbus A380 current speed: 556mph\n", "24/08/2020 10:05:00: Airbus A380 current speed: 526mph\n", "24/08/2020 10:05:01: Airbus A380 current speed: 496mph\n", "24/08/2020 10:05:02: Airbus A380 current speed: 466mph\n", "24/08/2020 10:05:03: Airbus A380 current speed: 436mph\n", "24/08/2020 10:05:04: Airbus A380 current speed: 406mph\n", "24/08/2020 10:05:05: Airbus A380 current speed: 376mph\n", "24/08/2020 10:05:06: Airbus A380 current speed: 346mph\n", "24/08/2020 10:05:07: Airbus A380 current speed: 316mph\n", "24/08/2020 10:05:08: Airbus A380 current speed: 286mph\n", "24/08/2020 10:05:09: Airbus A380 current speed: 256mph\n", "24/08/2020 10:05:10: Airbus A380 current speed: 226mph\n", "24/08/2020 10:05:11: Airbus A380 current speed: 196mph\n", "24/08/2020 10:05:12: Airbus A380 current speed: 166mph\n", "24/08/2020 10:05:13: Airbus A380 current speed: 150mph\n", "None\n" ] } ], "source": [ "# Invoke a method that is defined in the Aircraft class that overrides a method defined in the Vehicle superclass\n", "print(airbus_a380.brake())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.6. Method Resolution Order" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [], "source": [ "# Define a simple superclass\n", "class ClassA:\n", " \n", " var1 = 'A'\n", " \n", " def __init__(self, a1, a2, a3):\n", " self.attr1 = a1\n", " self.attr2 = a2\n", " self.attr3 = a3\n", " \n", " def method1(self):\n", " return self.attr1 + self.attr2\n", "\n", "\n", "# Define a simple class derived from ClassA\n", "class ClassB(ClassA):\n", " \n", " var1 = 'B'\n", " \n", " def __init__(self, b1, b2, b3):\n", " super().__init__(b1, b2, b3)\n", " self.attr4 = b2 * b3\n", " \n", " def method1(self):\n", " return self.attr1 * self.attr2\n", "\n", "\n", "# Define another simple class derived from ClassA\n", "class ClassC(ClassA):\n", " \n", " def __init__(self, c1, c2, c3):\n", " super().__init__(c1, c2, c3)\n", " self.attr4 = c2 - c3\n", " \n", " def method1(self):\n", " return self.attr1 - self.attr2\n", "\n", "\n", "# Define a class that is derived from both ClassB and ClassC\n", "class ClassD(ClassB, ClassC):\n", " pass" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ClassB attr1: 1\n", "ClassB attr2: 2\n", "ClassB attr3: 3\n", "ClassB attr4: 6\n", "ClassB var1: B\n", "ClassB method1(): 2\n" ] } ], "source": [ "# Create and test an instance of ClassB\n", "class_b_object = ClassB(1, 2, 3)\n", "print(f'ClassB attr1: {class_b_object.attr1}')\n", "print(f'ClassB attr2: {class_b_object.attr2}')\n", "print(f'ClassB attr3: {class_b_object.attr3}')\n", "print(f'ClassB attr4: {class_b_object.attr4}')\n", "print(f'ClassB var1: {class_b_object.var1}')\n", "print(f'ClassB method1(): {class_b_object.method1()}')" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ClassC attr1: 1\n", "ClassC attr2: 2\n", "ClassC attr3: 3\n", "ClassC attr4: -1\n", "ClassC var1: A\n", "ClassC method1(): -1\n" ] } ], "source": [ "# Create and test an instance of ClassC\n", "class_c_object = ClassC(1, 2, 3)\n", "print(f'ClassC attr1: {class_c_object.attr1}')\n", "print(f'ClassC attr2: {class_c_object.attr2}')\n", "print(f'ClassC attr3: {class_c_object.attr3}')\n", "print(f'ClassC attr4: {class_c_object.attr4}')\n", "print(f'ClassC var1: {class_c_object.var1}')\n", "print(f'ClassC method1(): {class_c_object.method1()}')" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ClassD attr1: 1\n", "ClassD attr2: 2\n", "ClassD attr3: 3\n", "ClassD attr4: 6\n", "ClassD var1: B\n", "ClassD method1(): 2\n" ] } ], "source": [ "# Create and test an instance of ClassD\n", "class_d_object = ClassD(1, 2, 3)\n", "print(f'ClassD attr1: {class_d_object.attr1}')\n", "print(f'ClassD attr2: {class_d_object.attr2}')\n", "print(f'ClassD attr3: {class_d_object.attr3}')\n", "print(f'ClassD attr4: {class_d_object.attr4}')\n", "print(f'ClassD var1: {class_d_object.var1}')\n", "print(f'ClassD method1(): {class_d_object.method1()}')" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ClassA MRO:\n", "(, )\n", "\n", "ClassB MRO:\n", "(, , )\n", "\n", "ClassC MRO:\n", "(, , )\n", "\n", "ClassD MRO:\n", "(, , , , )\n", "\n" ] } ], "source": [ "# Access the resolved MRO for each class\n", "print(f'ClassA MRO:\\n{ClassA.__mro__}\\n')\n", "print(f'ClassB MRO:\\n{ClassB.__mro__}\\n')\n", "print(f'ClassC MRO:\\n{ClassC.__mro__}\\n')\n", "print(f'ClassD MRO:\\n{ClassD.__mro__}\\n')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.7. Finding Subclasses" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['RoadVehicle', 'Aircraft']\n", "[, ]\n" ] } ], "source": [ "# List the names of all the subclasses directly derived from the Vehicle class\n", "print([cls.__name__ for cls in Vehicle.__subclasses__()])\n", "\n", "# List all the subclasses directly derived from the Vehicle class\n", "print(Vehicle.__subclasses__())" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{, , }\n" ] } ], "source": [ "# Create a function to list all direct and indirect subclasses of a given class\n", "def find_all_subclasses(cls):\n", " return set(cls.__subclasses__()).union(\n", " [subclass for c in cls.__subclasses__() for subclass in find_all_subclasses(c)])\n", "\n", "# List all the subclasses that are both directly and indirectly derived from the Vehicle class\n", "print(find_all_subclasses(Vehicle))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.4. Constructors\n", "#### 2.4.2. Non-Parameterized Constructor" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Creating an instance of ClassX...\n", "138\n" ] } ], "source": [ "# Define a class with a non-parameterized constructor\n", "class ClassX:\n", " \n", " def __init__(self):\n", " print(f'Creating an instance of {type(self).__name__}...')\n", " \n", " def sum(self, a, b):\n", " return a + b\n", " \n", "# Create a new instance of ClassX\n", "class_x_object = ClassX()\n", "\n", "# Invoke a method on the new object of type ClassX\n", "print(class_x_object.sum(100, 38))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.4.3. Default Constructor" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "260\n" ] } ], "source": [ "# Define a class without an explicit constructor\n", "class ClassY:\n", " \n", " def product(self, a, b):\n", " return a * b\n", "\n", "# Create a new instance of ClassY\n", "class_y_object = ClassY()\n", "\n", "# Invoke a method on the new object of type ClassY\n", "print(class_y_object.product(13, 20))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.4.4. Explicit Invocation" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Creating an instance of ClassZ...\n", "3\n" ] } ], "source": [ "# Define a class with a constructor that explicitly invokes the constructor of another class\n", "class ClassZ:\n", " \n", " def __init__(self):\n", " ClassX.__init__(self)\n", " \n", " def modulus(self, a, b):\n", " return a % b\n", "\n", "# Create a new instance of ClassZ\n", "class_z_object = ClassZ()\n", "\n", "# Invoke a method on the new object of type ClassZ\n", "print(class_z_object.modulus(103, 4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.5. Name Mangling" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "04/08/1961\n" ] } ], "source": [ "# Define a class that contains 'private' variables\n", "class User:\n", " \n", " def __init__(self, fname, lname, email, dob, postal_address):\n", " self.fname = fname\n", " self.lname = lname\n", " self.email = email\n", " self.__dob = dob\n", " self.__postal_address = postal_address\n", " \n", " def display_dob(self):\n", " print(self.__dob)\n", " \n", " def display_postal_address(self):\n", " print(self.__postal_address)\n", "\n", "# Create a new user\n", "barack_obama_user = User('Barack', 'Obama', 'bobama@whitehouse.gov', '04/08/1961', '1600 Pennsylvania Avenue')\n", "\n", "# Display the user's private dob using the display_dob() method\n", "barack_obama_user.display_dob()" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'User' object has no attribute 'dob'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Display the user's private dob by directly accessing the dob attribute using dot notation\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbarack_obama_user\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdob\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'User' object has no attribute 'dob'" ] } ], "source": [ "# Display the user's private dob by directly accessing the dob attribute using dot notation\n", "print(barack_obama_user.dob)" ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "04/08/1961\n" ] } ], "source": [ "# Display the user's private dob indirectly by accessing the mangled dob attribute\n", "print(barack_obama_user._User__dob)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.6. Common Functions" ] }, { "cell_type": "code", "execution_count": 180, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "True\n", "True\n", "False\n", "True\n", "True\n", "True\n", "True\n", "True\n", "True\n", "True\n", "False\n", "True\n", "\n", "True\n", "True\n", "True\n", "False\n", "True\n" ] } ], "source": [ "# Create a new aircraft object\n", "airbus_a380 = Aircraft(number_engines = 4,\n", " engine_horsepower_kw = 670,\n", " chassis_height_mm = 24100,\n", " chassis_width_mm = 79800,\n", " chassis_depth_mm = 72700,\n", " make = 'Airbus',\n", " model = 'A380',\n", " year_manufactured = 2005,\n", " maximum_speed_mph = 736,\n", " acceleration_rate_mps = 30,\n", " deceleration_rate_mps = 30,\n", " minimum_speed_mph = 150)\n", "\n", "# hasattr()\n", "print( hasattr(airbus_a380, 'engine_horsepower_kw') )\n", "print( hasattr(airbus_a380, 'last_mot_date') )\n", "print()\n", "\n", "# type()\n", "print( type(airbus_a380) )\n", "print( type([1, 2, 3]) )\n", "print( type(('a', 'b', 'c')) )\n", "print( type({1: 'a', 2: 'b', 3: 'c'}) )\n", "print( type(Vehicle) )\n", "print( type(str) )\n", "print( type(int) )\n", "print( type(str) )\n", "print( type('Hello World!') )\n", "print( type(38) )\n", "print( type(0.5) )\n", "print( type(True) )\n", "print( type(False) )\n", "print( type(47 & 55) )\n", "print( type(None) )\n", "print()\n", "\n", "# issubclass()\n", "print( issubclass(type(airbus_a380), Vehicle) )\n", "print( issubclass(Aircraft, Vehicle) )\n", "print( issubclass(Vehicle, Aircraft) )\n", "print( issubclass(Vehicle, Vehicle) )\n", "print( issubclass(Vehicle, object) )\n", "print( issubclass(str, object) )\n", "print( issubclass(list, object) )\n", "print( issubclass(tuple, object) )\n", "print( issubclass(dict, object) )\n", "print( issubclass(type(ClassD(1, 2, 3)), ClassA) )\n", "print( issubclass(type(None), ClassA) )\n", "print( issubclass(type(None), object) )\n", "print()\n", "\n", "# isinstance()\n", "print( isinstance(airbus_a380, Aircraft) )\n", "print( isinstance(airbus_a380, Vehicle) )\n", "print( isinstance(airbus_a380, object) )\n", "print( isinstance(airbus_a380, Car) )\n", "print( isinstance(None, object) )" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" } }, "nbformat": 4, "nbformat_minor": 4 }