{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Inheritance\n",
"\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
}