Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 1 addition & 168 deletions concepts/class-inheritance/about.md
Original file line number Diff line number Diff line change
@@ -1,168 +1 @@
# 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 its 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
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
```
### 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

# TODO: Add about for this concept.
11 changes: 8 additions & 3 deletions concepts/class-inheritance/introduction.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# 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.
[`Inheritance`][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 `class`es, and can help make programs cleaner and more maintainable.


[inherit]:https://realpython.com/inheritance-composition-python/#whats-inheritance
`Inheritance` describes an ["is a kind of"][is-a] relationship between two or more `class`es.
Common or more "generic" features are abstracted into a `super class` (also known as a _base class_ or _parent class_), and more specific details, behaviors, and data are detailed/extended in one or more `subclass`es (also known as _derived classes_ or _child classes_).

[inheritance]: https://algomaster.io/learn/python/single-inheritance
[four-pillars]: https://www.altcademy.com/blog/what-is-object-oriented-programming-in-python/#the-pillars-of-oop
[is-a]: https://en.wikipedia.org/wiki/Is-a
Loading