Knowledge Supplement 3: Python -- class inheritance

Posted by dacio on Thu, 03 Feb 2022 20:02:58 +0100

Foundation of class

class Dog:
    # This class is created from white space, so there are no parentheses in the definition
    # The first letter of the class should be capitalized
    def __init__(self, name, age):
        # init has two underscores on both sides, which is a special method
        # This method is defined to contain three formal parameters (the first one must be self)
        # When a new instance is created according to the Dog class, this method will be called automatically and the argument self will be passed in automatically
        # Just provide values for the following formal parameters (name and age)
        # Each method call associated with an instance automatically passes the argument self, which is a reference to the instance itself, so that the instance can access the properties and methods in the class
        self.name = name
        self.age = age
        # Variables prefixed with self can be used by all methods in the class
        # It can also be accessed through any instance of the class (variables of this class are called properties)

    def sit(self):
        # This method requires no additional information, so there is only one formal parameter self
        print(f"{self.name} is now sitting.")

    def roll_over(self):
        print(f'{self.name} rolled over!')


jack = Dog('Jack', 18)
# Create instance
jack.name
# Access properties
jack.sit()
jack.roll_over()
# Call method

Properties of class

class User:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
        self.age = 18
        # Specify default attribute values

    def describe_user(self):
        print(self.first_name, self.last_name)

    def greet_user(self):
        print(f'Hello, {self.first_name} {self.last_name}')

    def update_age_1(self, age):
        if age >= self.age:
            self.age = age
        else:
            print('The newly set age cannot be younger than the previous one')

    def update_age_2(self, age):
        self.age += age

    def update_age_3(self):
        self.age += 1


myself = User('Hugo', 'Ho')
myself.describe_user()
myself.greet_user()
print(myself.age)
myself.age = 20
print(myself.age)
# Directly modify the value of the attribute
myself.update_age_1(29)
print(myself.age)
# Modify the value of an attribute through the method
myself.update_age_2(11)
print(myself.age)
# Increment the value of the attribute by method (custom value)
myself.update_age_3()
print(myself.age)
# Increment the value of the attribute by method (fixed value)

Class inheritance

When writing classes, you can start with blank space or use inheritance (a new class is a special version of an existing class).

  • When a class inherits from another class, it will automatically obtain all the properties and methods of the other class (you can also define your own properties and methods).
  • The original class is called the parent class, while the new class is called the child class.

Subclass method__ init__ ()

When you write a subclass based on the parent class, you usually call the methods of the parent class__ init__ (). This will initialize in the parent class__ init__ () method, so that subclasses contain these properties.

In the following code, the subclass ElectricCar is written on the basis of the parent Car, so that the latter has all the functions of the former:

class Car:
# When creating a subclass, the parent class must be included in the current file and in front of the subclass
    def __init__(self, make, model, year):
        """Initialize the properties that describe the car"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0

    def get_descriptive_name(self):
        """Returns full descriptive information"""
        long_name = f'{self.year} {self.make} {self.model}'
        return long_name.title()

    def read_odometer(self):
        """Print a piece of car mileage information"""
        print(f'This car has {self.odometer_reading} miles on it.')

    def update_odometer(self, mileage):
        """
        Set the odometer reading to the specified value.
        It is forbidden to callback the odometer reading.
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print('You can`t roll back an odometer!')

    def increment_odometer(self, miles):
        """Increase the odometer reading by the specified amount"""
        self.odometer_reading += miles


class ElectricCar(Car):
# When defining a subclass, you must specify the name of the parent class within parentheses
    """The uniqueness of electric vehicles."""

    def __init__(self, make, model, year):
    # Method__ init__ () receive the information needed to create the Car instance
        """Initializes the properties of the parent class"""
        super().__init__(make, model, year)
        # super() is a special function that can call the parent class method
        # Here, the super() function calls the method of the Car class__ init__ (), let the ElectricCar instance contain all the attributes defined in this method
        # The parent class is also called superclass, from which the name super comes


my_tesla = ElectricCar('tesla', 'model s', 2019)
# Create an electrocar instance and assign it to the variable my_tesla
# This line of code will automatically call the method defined in the subclass ElectricCar__ init__ (), which will make Python call the methods defined in the parent class Car__ init__ ()
print(my_tesla.get_descriptive_name())

Output:

2019 Tesla Model S

Define properties and methods for subclasses

After the subclass inherits the parent class, you can add new properties and methods to distinguish it from the parent class.

class Car: 
    --snip--

class ElectricCar(Car):
    """The uniqueness of electric vehicles."""

    def __init__(self, make, model, year):
        """
        Initializes the properties of the parent class.
        Initializes subclass specific properties.
        """
        super().__init__(make, model, year)
        self.battery_size = 75
        # Add a new attribute of the subclass (all instances created from the ElectricCar class contain this attribute, while instances of other Car classes do not)

    def describe_battery(self):
    # New method for adding subclasses
        """Print a message describing the battery capacity."""
        print(f"This car has a {self.battery_size}-kWh battery.")


my_tesla = ElectricCar('tesla', 'model s', 2019)
# Create an instance of electrocar
print(my_tesla.get_descriptive_name())
# Call the method that the subclass inherits from the parent class
my_tesla.describe_battery()
# Call your own subclass

Output:

2019 Tesla Model S
This car has a 75-kWh battery.

Override the method of the parent class

You can define a method in a subclass that has the same name as the parent method you want to override.

class Car:
    --snip--

class ElectricCar(Car):
    """The uniqueness of electric vehicles."""

    def __init__(self, make, model, year):
        """
        Initializes the properties of the parent class.
        Initializes subclass specific properties.
        """
        super().__init__(make, model, year)
        self.battery_size = 75

    def describe_battery(self):
        """Print a message describing the battery capacity."""
        print(f"This car has a {self.battery_size}-kWh battery.")

    def get_descriptive_name(self):
        """Return complete descriptive information (with new energy logo)."""
        long_name = f'[new energy] {self.year} {self.make} {self.model}'
        # Override the method with the same name in the parent class and mark it with "[new energy]"
        return long_name.title()


my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
# At this point, Python no longer considers the parent method, but only the corresponding method defined in the subclass
my_tesla.describe_battery()

[new energy] 2019 Tesla Model S
This car has a 75-kWh battery.

Use instances as properties

You can extract a part of a class as an independent class (split a large class into multiple small classes that work together).

Next, extract some attributes and methods of electrocar, put them into a class named Battery, and take an instance of Battery as the attributes of electrocar class.

class Car:
    --snip--

class ElectricCar(Car):
    """The uniqueness of electric vehicles."""

    def __init__(self, make, model, year):
        """
        Initializes the properties of the parent class.
        Initializes subclass specific properties.
        """
        super().__init__(make, model, year)
        self.battery = Battery()
        # Add a new attribute and connect the Battery class (create an instance of the Battery class, which will be executed whenever the method _init _ is called)
        # Each electrocar instance now contains an automatically created Battery instance

    def get_descriptive_name(self):
        """Return complete descriptive information (with new energy logo)."""
        long_name = f'[new energy] {self.year} {self.make} {self.model}'
        return long_name.title()


class Battery:
# Define a new class named Battery (without inheriting any classes)
    """Related properties and methods of electric vehicle battery."""

    def __init__(self, battery_size=75):
    # Add formal parameter battery_size. If no value is provided, the default battery capacity is 75
        """Initialize battery properties"""
        self.battery_size = battery_size

    def describe_battery(self):
        """Print a message describing the battery capacity."""
        print(f"This car has a {self.battery_size}-kWh battery.")


my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
# When describing the battery, you need to use the attribute battery of the electrocar class

Output:

[new energy] 2019 Tesla Model S
This car has a 75-kWh battery.

Modify the value of the instance (property) of the instance (class)

class Car:
    --snip--

class ElectricCar(Car):
    --snip--

class Battery:
    --snip--

my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.battery_size = 100
# By modifying the value of the attribute (battery_size) in the attribute (battery) in the instance (my_tesla) of electrocar
my_tesla.battery = Battery(100)
# Modify the parameter value of the instance (battery) corresponding to the attribute (battery) in the instance (my_tesla) of electrocar
my_tesla.battery.describe_battery()

Output:

[new energy] 2019 Tesla Model S
This car has a 100-kWh battery.

A car is composed of many modules. If you want to describe each module in detail, it's best to arrange different modules in different classes, and then insert these classes into the attributes of a general class in the form of instances, which can be called when necessary.

Next, add a method to the Battery class, which can report the mileage of the car according to the Battery capacity.

class Car:
    --snip--

class ElectricCar(Car):
    --snip--

class Battery:
    """Related properties and methods of electric vehicle battery."""

    def __init__(self, battery_size=75):
        """Initialize battery properties"""
        self.battery_size = battery_size

    def describe_battery(self):
        """Print a message describing the battery capacity."""
        print(f"This car has a {self.battery_size}-kWh battery.")

    def get_nedc(self):
    # The new method makes a simple analysis and reports the mileage according to the battery capacity
        """Print a message describing the battery range"""
        if self.battery_size == 75:
            nedc = 260
        elif self.battery_size == 100:
            nedc = 315
        print(f"This car can go about {nedc} miles on a full charge.")


my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
# my_tesla.battery.battery_size = 100
my_tesla.battery.describe_battery()
my_tesla.battery.get_nedc()
# Get the information by calling the method of the instance's property

Output:

[new energy] 2019 Tesla Model S
This car has a 75-kWh battery.
This car can go about 260 miles on a full charge.

Class import

Import multiple classes from a module

from car import Car, ElectricCar


my_beetle = Car('volkswagen', 'beetle', 2019)

my_tesla = Car('tesla', 'roadster', 2019)

Import the entire module

import Car

my_beetle = car.Car('volkswagen', 'beetle', 2019)

my_tesla = car.ElectricCar('tesla', 'roadster', 2019)

Import all classes in the module

from car import *
# Not recommended
# It is not clear at a glance which classes in the module are used
# Cause confusion about the name (an error will be generated if a class with the same name appears)
# It is recommended to import the whole module and then use the syntax of "module name. Class name" to access the class

Import classes and specify aliases

from electric_car import ElectricCar as EC

my_tesla = EC('tesla', 'roadster', 2019)

Coding style of class

  • The class name adopts the hump naming method: the first letter of each word is capitalized without underline (the instance name and module name are in lowercase format, and underline is added between words)
  • Both the end of the class definition and the beginning of the module are followed by a document string that briefly describes the functions of the class
  • In the module, there are two empty lines between two classes. In a class, there is a blank line between two methods.
  • First import the module of the standard library, and then import the module written by yourself

< end >

Topics: Python Back-end