diff --git a/concepts/class-inheritance/.meta/config.json b/concepts/class-inheritance/.meta/config.json index 9b9e8da5a9..f6bf6d7d87 100644 --- a/concepts/class-inheritance/.meta/config.json +++ b/concepts/class-inheritance/.meta/config.json @@ -1,5 +1,5 @@ { - "blurb": "TODO: add blurb for this concept", - "authors": ["bethanyg", "cmccandless"], - "contributors": [] + "blurb": "In Object Oriented Programming ('OOP'), inheritance refers to a class's capacity to copy or 'inherit' properties and methods from another class. Python allows inheritance from a single class or multiple classes. Existing classes are known as base (or parent) classes, and new classes are known as derived (or child) classes.", + "authors": ["girijakar", "bethanyg"], + "contributors": [ ] } diff --git a/concepts/class-inheritance/about.md b/concepts/class-inheritance/about.md index c628150d56..5db7909e2c 100644 --- a/concepts/class-inheritance/about.md +++ b/concepts/class-inheritance/about.md @@ -1,2 +1,168 @@ -#TODO: Add about for this concept. +# About + +Inheritance is one of the ['four pillars'][four-pillars] of Object Oriented Programming (`OOP`). +In situations where only a small amount of functionality needs to be customized for a new class, `inheritance` allows code re-use from one or more parent classes, and can help make programs cleaner and more maintainable. + +## Inheritance + +`Inheritance` describes `is a kind of` relationship between two or more classes, abstracting common details into super (_base_ or _parent_) class and storing specific ones in the subclass (_derived class_ or _child class_). + +To create a child class, specify the parent class name inside the pair of parenthesis, followed by it's name. +Example +```python +class Child(Parent): + pass +``` +Every child class inherits all the behaviors (_attributes, constructors, methods_) exhibited by their parent class. + + +## Single Inheritance + +When a derived (or child) class inherits only from one base (or parent) class, it is known as _single inheritance_. + + +```python +# The parent or base class. +class Person: + + def __init__(self, fname, lname): + self.fname = fname + self.lname = lname + +# The child or derived class, inheriting from Person. +class Employee(Person): + + all_employees = [] + def __init__(self, fname, lname, empid): + # Using the Parent constructor to create the base object. + Person.__init__(self, fname, lname) + + # Adding an attribute specific to the Child class. + self.empid = empid + + Employee.all_employees.append(self) +``` +`Employee` class is derived from `Person`. +Now, we can create an `Employee` object. + + +```python +... +p1 = Person('George', 'smith') +print(p1.fname, '-', p1.lname) +e1 = Employee('Jack', 'simmons', 456342) +e2 = Employee('John', 'williams', 123656) +print(e1.fname, '-', e1.empid) +print(e2.fname, '-', e2.empid) +``` +After running the program we will get the following output +```bash + +George - smith +Jack - 456342 +John - 123656 +``` +## Multiple Inheritance +As we've seen, `single inheritance` is where a class inherits directly from another class. +On the other side, `multiple inheritance` is a Python feature that allows a child class to inherit characteristics and methods from more than one parent class. + +```python +class SubclassName(BaseClass1, BaseClass2, ...): + pass +``` +### Multiple Inheritance and the Diamond Problem + +The "diamond problem" (also known as the "deadly diamond of death") refers to an ambiguity that occurs when two classes B and C inherit from a superclass A, while another class D inherits from both B and C. If A has a method "m" that B or C (or even both of them) has overridden, and if it does not override this method, the question becomes which version of the method D inherits. It's possible that it's from A, B, or C. +Let's have a look at the problem using an example: + +```python +class A: + def m(self): + print("m of A called") +class B(A): + def m(self): + print("m of B called") +class C(A): + def m(self): + print("m of C called") +class D(B,C): + pass +``` +If we call an instance x of class D, we will get the output as `m of B called`. But if we interchange the order of inheritance in class D i.e. `Class D(C, D)`. We will get the output as `m of C called`. +To solve the diamond problem in python, we will look into a new method `mro()`. +### Method resolution order(MRO) + +To get the method resolution order of a class we can use either `__mro__` attribute or `mro()` method. By using these methods we can display the order in which methods are resolved. For Example + +```python +class A: + def m(self): + print(" m of A called") +class B: + def m(self): + print(" m of B called") + +# classes ordering +class C(A, B): + def __init__(self): + print("Constructor C") + +r = C() + +# it prints the lookup order +print(C.__mro__) +print(C.mro()) +``` +The output +```cmd +Constructor C +(, , , ) +[, , , ] +``` +### Mixins +A mixin is a type of multiple inheritance that is unique. Mixins are typically employed in one of two scenarios: + +1. We wish to give a class a number of optional features. +1. We want to use a specific feature in a variety of classes. + +For example +```python +class A1(object): + def method(self): + return 1 + +class A2(object): + def method(self): + return 2 + +class B1(object): + def usesMethod(self): + return self.method() + 10 + +class B2(object): + def usesMethod(self): + return self.method() + 20 + +class C1_10(A1, B1): pass +class C1_20(A1, B2): pass +class C2_10(A2, B1): pass +class C2_20(A2, B2): pass +``` +Mixins helps us to recombine functionalities with different choices of base classes. +#### Pros and Cons of Mixins +| Advantages | Disadvantages | +|:-- | :-- | +|Mixin classes tend to be simple because they represent simple orthogonal concepts. | Execution of statements at run time tends to jump around in different mixins, making it hard to follow and debug| +|Helps us to recombine functionalities with different choices | Potential for long compile times| +## __super()__ +In a nutshell, `super()` gives us access to methods in a superclass from the subclass that inherits from it. +`super()` by itself returns a temporary object of the superclass, which may subsequently be used to call the methods of that superclass. + +But why we want to use `super()`? + +Using `super()` to call already created methods avoids having to rebuild those methods in our subclass and allows us to swap out superclasses with little code modifications. + +[four-pillars]: https://www.educative.io/edpresso/what-are-the-four-pillars-of-oops-in-python + +[four-pillars]: https://www.educative.io/edpresso/what-are-the-four-pillars-of-oops-in-python diff --git a/concepts/class-inheritance/introduction.md b/concepts/class-inheritance/introduction.md index fcde74642c..fb1cfff6e4 100644 --- a/concepts/class-inheritance/introduction.md +++ b/concepts/class-inheritance/introduction.md @@ -1,2 +1,7 @@ -#TODO: Add introduction for this concept. +# Introduction +[Inheritance](inherit) represents what is known as a relationship. When a Derived class inherits from a Base class, you've established a relationship in which Derived is a specialised version of Base. +Either by using single or multiple inheritance, we can inherit the properties from the base class. Inheritance is used because it helps in code reusability. + + +[inherit]:https://realpython.com/inheritance-composition-python/#whats-inheritance diff --git a/concepts/class-inheritance/links.json b/concepts/class-inheritance/links.json index eb5fb7c38a..034b9b3935 100644 --- a/concepts/class-inheritance/links.json +++ b/concepts/class-inheritance/links.json @@ -1,18 +1,42 @@ [ { - "url": "http://example.com/", - "description": "TODO: add new link (above) and write a short description here of the resource." + "url": "https://docs.python.org/3/tutorial/classes.html", + "description": "Classes in python" }, { - "url": "http://example.com/", - "description": "TODO: add new link (above) and write a short description here of the resource." + "url": "https://www.geeksforgeeks.org/access-modifiers-in-python-public-private-and-protected/", + "description": "Access Modifiers in python" }, { - "url": "http://example.com/", - "description": "TODO: add new link (above) and write a short description here of the resource." + "url": "https://www.geeksforgeeks.org/accessor-and-mutator-methods-in-python/", + "description": "Functions in classes" }, { - "url": "http://example.com/", - "description": "TODO: add new link (above) and write a short description here of the resource." + "url": "https://realpython.com/inheritance-composition-python/#whats-inheritance", + "description": "About inheritance" + }, + { + "url": "https://python-course.eu/oop/multiple-inheritance.php", + "description": "Multiple inheritance and Diamond inheritance problem" + }, + { + "url": "https://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful", + "description": "Python mixins" + }, + { + "url": "https://raganwald.com/2016/07/16/why-are-mixins-considered-harmful.html", + "description": "Mixins cons" + }, + { + "url": "https://gaopinghuang0.github.io/2018/12/29/dig-into-python-super-and-mro", + "description": "Super and mixins functions" + }, + { + "url": "https://www.python.org/download/releases/2.3/mro/", + "description": "MRO" + }, + { + "url": "https://nedbatchelder.com/blog/201210/multiple_inheritance_is_hard.html", + "description": "Multiple inheritancs and mixins" } ]