Core Python / Inheritance#
What is inheritance in the context of object-oriented programming, why is it useful, and how is it implemented in Python?
Inheritance in object-oriented programming (OOP) is a mechanism where a new class (called a child or subclass) is derived from an existing class (called a parent or superclass). The child class inherits attributes and methods from the parent class, allowing for code reuse and the creation of more complex systems by building on existing code.
Code Reuse: By inheriting from existing classes, you can reuse code without having to rewrite it, which reduces redundancy.
Extensibility: You can extend the functionality of existing classes. This makes it easier to add new features.
Maintainability: Inheritance helps in organizing code into a hierarchical structure, making it easier to manage and understand.
Polymorphism: Inheritance allows for polymorphism, where a single function or method can work in different ways depending on the object it is acting upon.
Inheritance is implemented by defining a new class that includes the name of the parent class in parentheses after the new class name.
Let’s create a parent class
Investment
and two child classesStock
andBond
that inherit fromInvestment
.class Investment: def __init__(self, name, principal): self.name = name self.principal = principal def get_value(self): return self.principal class Stock(Investment): def __init__(self, name, principal, shares, share_price): super().__init__(name, principal) self.shares = shares self.share_price = share_price def get_value(self): return self.shares * self.share_price class Bond(Investment): def __init__(self, name, principal, interest_rate, years): super().__init__(name, principal) self.interest_rate = interest_rate self.years = years def get_value(self): return self.principal * (1 + self.interest_rate) ** self.years # Example usage stock = Stock('TechCorp', 10000, 100, 150) bond = Bond('GovBond', 10000, 0.05, 10) print("Stock Value: {}".format(stock.get_value())) # Output: 15000 (100 shares * $150 per share) print("Bond Value: {}".format(bond.get_value())) # Output: 16288.95 (Compound interest calculation)
Parent Class (
Investment
): This class includes common attributes likename
andprincipal
and a methodget_value
that simply returns the principal amount. This method can be overridden by subclasses to provide more specific behavior.Child Class (
Stock
): This class extendsInvestment
. It has additional attributes such asshares
andshare_price
. It overrides theget_value
method to calculate the value of the stock based on the number of shares and the share price.Child Class (
Bond
): This class also extendsInvestment
. It includes attributes likeinterest_rate
andyears
. Theget_value
method is overridden to calculate the bond’s value using compound interest.
How do you create a subclass that inherits from a parent class in Python? Explain the difference from a regular class.
In Python, creating a subclass that inherits from a parent class involves using the syntax
class SubClassName(ParentClassName):
. Differences from a regular class:Inheritance: Subclassing allows a new class to inherit properties and behavior from an existing class (the parent or base class). This promotes code reusability and modularity.
Access to Parent Class Features: Subclasses have access to all the methods and attributes of the parent class, which can be used directly or overridden (redefined) as needed.
Overriding Methods: Subclasses can override methods of the parent class to provide specialized behavior.
get_value()
in the prior answer exemplifies this.Extension: Subclasses can extend the functionality of the parent class by adding new methods or attributes.
super() Function: The
super()
function is used to call methods and constructors of the parent class within the subclass. This allows subclasses to reuse the functionality of the parent class while still customizing behavior.Inheritance Hierarchy: Subclasses can themselves be subclassed, creating a hierarchy of classes. Each subclass inherits from its immediate parent and all ancestors in the chain.
What is the purpose of the super() function when working with inheritance in Python?
The purpose of the
super()
function in Python is to access and call methods or constructors from the parent class within a subclass. It allows for cooperative multiple inheritance, ensuring that all necessary initialization and behavior from parent classes are properly executed. This promotes code reuse and maintains the integrity of the inheritance chain.What is method overriding, and how is it achieved in Python?
Method overriding is the process of redefining a method in a subclass that was already defined in the parent class. It allows the subclass to provide its own implementation of the method while retaining the same method signature (name and parameters) as the parent class. In Python, method overriding is achieved simply by defining a method in the subclass with the same name as the method in the parent class. When an object of the subclass calls the overridden method, the subclass’s implementation is executed instead of the parent class’s implementation.
What is the difference between single inheritance, multiple inheritance, and multilevel inheritance?
Single Inheritance: In single inheritance, a subclass inherits from only one parent class. This is the simplest form of inheritance and is commonly used in many programming scenarios.
Multiple Inheritance: Multiple inheritance occurs when a subclass inherits from more than one parent class. This allows the subclass to inherit attributes and methods from multiple sources. While powerful, it can lead to complexity and potential conflicts if not managed carefully.
Multilevel Inheritance: Multilevel inheritance involves a chain of inheritance where a subclass inherits from a parent class, and another subclass inherits from this derived class, forming a hierarchy. It represents a structure where each derived class serves as the parent for the next level of subclasses.
What is polymorphism in object-oriented programming, and how is it implemented in Python?
Polymorphism in object-oriented programming refers to the ability of different objects to respond to the same message (method call) in different ways. In Python, polymorphism is achieved through method overriding and duck typing. Method overriding allows subclasses to provide their own implementation of a method inherited from a parent class, while duck typing enables objects of different classes to be used interchangeably if they implement the same method interface. This flexibility allows for dynamic and versatile behavior in Python programs.
What is an abstract class, and how do you define one in Python?
An abstract class in object-oriented programming is a class that cannot be instantiated on its own and is designed to be subclassed. Abstract classes typically include abstract methods, which are methods that are declared but contain no implementation. Subclasses of the abstract class are required to implement these abstract methods. Abstract classes serve as blueprints for other classes and help enforce a consistent interface across different subclasses.
In Python, abstract classes are defined using the
abc
module, which stands for Abstract Base Classes.from abc import ABC, abstractmethod class Investment(ABC): def __init__(self, name, principal): self.name = name self.principal = principal @abstractmethod def get_value(self): pass class Stock(Investment): def __init__(self, name, principal, shares, share_price): super().__init__(name, principal) self.shares = shares self.share_price = share_price def get_value(self): return self.shares * self.share_price class Bond(Investment): def __init__(self, name, principal, interest_rate, years): super().__init__(name, principal) self.interest_rate = interest_rate self.years = years def get_value(self): return self.principal * (1 + self.interest_rate) ** self.years # Example usage stock = Stock('TechCorp', 10000, 100, 150) bond = Bond('GovBond', 10000, 0.05, 10) print("Stock Value: {}".format(stock.get_value())) # Output: 15000 print("Bond Value: {}".format(bond.get_value())) # Output: 16288.95
This example largely follows the same code from the first example, but with the
Investment
class declared as abstract.Importing
ABC
andabstractmethod
: TheABC
class from theabc
module is used to define an abstract base class. Theabstractmethod
decorator is used to declare abstract methods.Defining the Abstract Class (
Investment
): TheInvestment
class inherits fromABC
, making it an abstract class. It has a constructor to initialize common attributes likename
andprincipal
. Theget_value
method is decorated with@abstractmethod
, indicating that it must be implemented by any subclass.Subclassing the Abstract Class (
Stock
andBond
):Stock
andBond
are concrete classes that inherit fromInvestment
. They implement theget_value
method, providing specific calculations for stocks and bonds, respectively.Instantiating Subclasses: You can create instances of
Stock
andBond
, but you cannot create an instance ofInvestment
directly. If you try to instantiateInvestment
, Python will raise an error since it contains an abstract method.# This will raise a TypeError because Investment is abstract and cannot be instantiated investment = Investment('Generic', 10000)
This setup ensures that any subclass of
Investment
provides an implementation for theget_value
method, enforcing a consistent interface across different types of financial instruments.What is the purpose of abstract methods in abstract classes?
The purpose of abstract methods in abstract classes is to define a method signature without providing an implementation. Abstract methods serve as placeholders, ensuring that subclasses of the abstract class must implement these methods. These method interfaces enforce a contract, ensuring that all subclasses provide their own implementation of the abstract methods, promoting consistency and ensuring that the desired behavior is present in each subclass.
What is the diamond problem in multiple inheritance, and how is it resolved in Python?
The diamond problem, also known as the diamond inheritance issue, occurs in multiple inheritance when a subclass inherits from two or more classes that have a common ancestor. If the common ancestor’s methods or attributes are overridden in the parent classes, it can lead to ambiguity in the subclass due to conflicting method implementations.
In Python, the diamond problem is resolved using Method Resolution Order (MRO). Python’s MRO algorithm uses the ordering of the parent classes in the child class definition to create a repeatable search path to determine which method to use.
*What are mixins in Python, and how are they used in inheritance?
Mixins add specific functionality to classes through multiple inheritance. A mixin class is a type of class that provides methods to other classes but is not intended to stand alone. Instead, mixins are used to “mix in” additional behavior into other classes - in a flexible and decoupled manner.
Here’s an example of how to apply two mixins to the
Investment
class hierarchy:class LoggingMixin: """ provides logging functionality """ def log(self, message): print("[LOG]: {}".format(message)) class DiscountMixin: """ Adds discount calculation functionality """ def apply_discount(self, discount_rate): self.principal *= (1 - discount_rate) self.log("Applied discount of {}%: new principal is {}".format(discount_rate*100, self.principal) ) class Investment: def __init__(self, name, principal): self.name = name self.principal = principal def get_value(self): return self.principal class Stock(Investment, LoggingMixin, DiscountMixin): def __init__(self, name, principal, shares, share_price): super().__init__(name, principal) self.shares = shares self.share_price = share_price def get_value(self): return self.shares * self.share_price class Bond(Investment, LoggingMixin, DiscountMixin): def __init__(self, name, principal, interest_rate, years): super().__init__(name, principal) self.interest_rate = interest_rate self.years = years def get_value(self): return self.principal * (1 + self.interest_rate) ** self.years # Example usage stock = Stock('TechCorp', 10000, 100, 150) bond = Bond('GovBond', 10000, 0.05, 10) # Using LoggingMixin stock.log("Calculating stock value") bond.log("Calculating bond value") # Using DiscountMixin stock.apply_discount(0.1) # Apply 10% discount bond.apply_discount(0.05) # Apply 5% discount print("Stock Value: {}".format(stock.get_value())) # Output: 13500 (100 shares * $150 per share) print("Bond Value: {}".format(bond.get_value())) # Output: 15474.5 (after discount and interest)
How can you check if an instance is an instance of a particular class or its subclasses?
You can check if an instance is an instance of a particular class or its subclasses using the
isinstance()
function in Python. This function takes two arguments: the instance you want to check and the class (or tuple of classes) you want to check against. It returnsTrue
if the instance is an instance of the specified class or any of its subclasses, otherwise it returnsFalse
.class ParentClass: pass class SubClass(ParentClass): pass obj = SubClass() print(isinstance(obj, ParentClass)) # Output: True print(isinstance(obj, SubClass)) # Output: True print(isinstance(1, SubClass)) # Output: False
Which of these is a common tool that software engineers use to describe the design of their classes?
UML diagrams.
What will be the output of the following Python code?
class Test: def __init__(self): self.x = 0 class Derived_Test(Test): def __init__(self): Test.__init__(self) self.y = 1 b = Derived_Test() print(b.x,b.y)
0 1
What will be the output of the following Python code?
class A: def one(self): return self.two() def two(self): return 'A' class B(A): def two(self): return 'B' obj1=A() obj2=B() print(obj1.two(),obj2.two())
A B
Within an initializer methods (
__init__
), is it necessary to call the parent’s initializer method?Strictly speaking, no. However, any required behavior performed by the parent’s initiliazer method would not be executed.
Which of the following statements is not true about inheritance?
Inheritance allows us to inherit attributes from a child class.