{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Inheritance\n", "\"Open\n", "\n", "- http://openbookproject.net/thinkcs/python/english3e/inheritance.html\n", "- https://www.python-course.eu/python3_inheritance.php\n", "\n", "- powerful feature that facilitates code reuse mimicking real-world phenomena\n", "- ability to define a new class (child) that is modified version of an existing class (parent)\n", "- can add new methods and properties to a class without modifying the existing class\n", "- some imitation(s) if inheritance:\n", " - can make programs difficult to read\n", " - when method is invoked, it is sometimes not clear where to find its definition esp. in a large project relevant code may be scattered among several modules\n", "- see better example (a hand of cards) in the text\n", "- syntax:\n", "```\n", "class childClassName(parentClass1, baseClass2, ...):\n", " #code (attributes and methods)\n", " pass\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Single Inheritance\n", "- supported by almost all OOP langauges\n", "" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [], "source": [ "# by dafault all python class implicitly inherit from object base class\n", "class A(object):\n", " def __init__(self):\n", " self.a = \"A\"\n", " \n", " def printMe(self):\n", " print(\"A's printMe called!\")\n", " print('a = {}'.format(self.a))\n", " \n", " def sayHi(self):\n", " print('{} says HI!'.format(self.a))" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A's printMe called!\n", "a = A\n", "A says HI!\n" ] } ], "source": [ "obja = A()\n", "obja.printMe()\n", "obja.sayHi()" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [], "source": [ "# single inheritance\n", "class B(A):\n", " def __init__(self):\n", " # must explictly invoke base classes constructors\n", " # to inherit properties/attributes\n", " A.__init__(self) # try commenting this out\n", " self.b = 'B'\n", "\n", " def update(self):\n", " print(\"Attributes before modifaction: {} and {}\".format(self.a, self.b))\n", " self.a = 'AAA' #can modify inherited attributes\n", " print(\"Attributes after modification: {} and {}\".format(self.a, self.b))\n", " \n", " # overrides inherited printMe\n", " def printMe(self):\n", " print(\"B's printMe called\")\n", " print('a = {}'.format(self.a))" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Attributes before modifaction: A and B\n", "Attributes after modification: AAA and B\n" ] } ], "source": [ "objb = B()\n", "# shows that A's properties are inherited by B\n", "objb.update()" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "obja's property a = A\n", "objb's property a = AAA\n" ] } ], "source": [ "# object a's properties are independent from object b's properties\n", "print(\"obja's property a = {}\".format(obja.a))\n", "print(\"objb's property a = {}\".format(objb.a))" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AAA says HI!\n" ] } ], "source": [ "# B inherits A's sayHi()\n", "# what is the output of the following?\n", "objb.sayHi()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overriding\n", "- child class can redefine method that are inherited from parent class with the same name\n", "- e.g., printMe() method in class B overrides A's printMe\n", "- A's printme can still be called \n", " - syntax\n", " ```\n", " ClassName.method(object)\n", " ```" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "B's printMe called\n", "a = AAA\n" ] } ], "source": [ "objb.printMe()" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A's printMe called!\n", "a = A\n" ] } ], "source": [ "A.printMe(obja)" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A's printMe called!\n", "a = AAA\n" ] } ], "source": [ "A.printMe(objb)" ] }, { "cell_type": "code", "execution_count": 130, "metadata": {}, "outputs": [], "source": [ "# C inherits from B which inherits from A\n", "class C(B):\n", " def __init__(self):\n", " B.__init__(self)\n", " self.c = 'C'\n", " \n", " def printMe(self):\n", " print(\"C's printMe called:\")\n", " print(\"Attributes are {}, {}, {}\".format(self.c, self.b, self.a))\n", " " ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "C's printMe called:\n", "Attributes are C, B, A\n" ] } ], "source": [ "c1 = C()\n", "c1.printMe()" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A says HI!\n" ] } ], "source": [ "# sayHi() inherited from A\n", "c1.sayHi()" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Attributes before modifaction: A and B\n", "Attributes after modification: AAA and B\n" ] } ], "source": [ "c1.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multiple Inheritance\n", "- Python allows a class to derive/inherit from multiple base classes\n", " - similar to C++\n", "- Java doesn't allow it (it's messy!)\n", "" ] }, { "cell_type": "code", "execution_count": 153, "metadata": {}, "outputs": [], "source": [ "# not required to explictly inherit from object class\n", "class D:\n", " def __init__(self):\n", " self.a = 'AAAAA'\n", " self.d = 'D'\n", " \n", " def scream(self):\n", " print(\"D's scream() called:\")\n", " \n", "# class E inherits from class C and D\n", "class E(C, D):\n", " def __init__(self):\n", " # the order in which the base constructors are called matters!\n", " # same attributes of proior constructors are overridden by later constructors\n", " # e.g., try switching D and C's construntor calls\n", " D.__init__(self)\n", " C.__init__(self)\n", " self.e = 'E'\n", " \n", " def printMe(self):\n", " print(\"E's printMe called:\")\n", " print(\"Attributes are {}, {}, {}, {}, {}\".format(self.e, self.d, self.c, self.b, self.a))" ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "E's printMe called:\n", "Attributes are E, D, C, B, A\n" ] } ], "source": [ "e1 = E()\n", "e1.printMe()" ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "D's scream() called:\n" ] } ], "source": [ "e1.scream()" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A says HI!\n" ] } ], "source": [ "e1.sayHi()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## abc module - Abstract Base Classes\n", "- allows to define ABCs with abstract methods @abstractmethod decorators" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "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.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }