📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Уроки Python с нуля / #19 – Наследование, инкапсуляция, полиморфизм

Школа itProger / Программирование18:28

Transcription

Hello! In this lesson, we will explore the main concepts of OOP, specifically inheritance, polymorphism, and encapsulation.

Before we begin, I would like to recommend the website itprager.com. On this site, you will find code, homework assignments, and a lot of other useful information. The link to this lesson on the site will be in the description of this video.

First, let's study the concept of inheritance. Inheritance is one of the most important concepts in OOP. It states that any class can have a subclass that inherits everything from its parent class, or in other words, from the superclass. A subclass is a class that is built on the basis of a parent class, and accordingly, this subclass inherits methods, fields, and various constructors.

Now, let's create a main class and an additional class that will inherit from it. Let's assume our main class describes all types of buildings, so I will name it "Building." In this class, we will include only general characteristics. For example, any building should have a year of construction, so we will specify a field for that. We will initially set the value to "nan."

Additionally, there should be a city where the building is located, so let's add a field called "city." You can add as many fields as you want, but for now, we will limit ourselves to these two characteristics.

I also want to add a constructor that will accept two parameters: the year and the city. In this constructor, we will simply assign the values we receive to the corresponding fields.

Furthermore, we might create a method called "getInfo." This method will output some information about the building. For instance, I will access the year and output it, as well as the city where the building is located.

So, what have we achieved? We have created a class that describes any building. Based on this class, we can easily create objects. For example, I can create an object called "School" that will be based on the "Building" class. I can pass specific characteristics, such as the year 2000 and a certain city, and everything will work correctly.

Now, let's imagine a situation where I create another object that describes a specific house, not a school, just a regular house. In the future, I might create another object for a kindergarten, and yet another for a store, and so on. All these objects will share the same general characteristics and methods.

However, suppose I need to add 5 or even 10 new functions specifically for the school. I can write all these functions in the school class without any issues, and it will work correctly. Later, I might find it necessary to add 10 new functions specifically for regular houses. Again, I would write all these new functions in the house class.

This could lead to a situation where my main class ends up with 30 additional functions, which can make the code difficult to read and understand.

It would be much more logical to create additional classes. For instance, if I create a new class called "School," this class will inherit everything from the "Building" class. It will have all the common characteristics defined in the parent class, plus its own additional functions and fields.

When we create a school object, we will do so based on the subclass, not the main class. This way, we will have access to all the common characteristics and those that belong specifically to the school.

We can do the same with a regular house and a store. Each of these subclasses will have its own functions and fields, allowing us to keep the main class free from unnecessary information.

Now, let's implement this. First, I will hide the "Building" class so it doesn't interfere with our work. Next, I will create a new class called "School," and I will indicate that it inherits from the "Building" class.

If we don't define anything in this class and simply write the keyword "pass," we can still create an object based on the "School" class. I can pass parameters to it, and if I run this, we will see that no errors occur.

Through this object, I can access all the characteristics defined in the main class. For example, I can access the year of construction or call the "getInfo" method. If I run this, everything will process correctly without any errors.

You can see that the "School" class does not have any methods or characteristics defined, yet everything works correctly because we inherit from the parent class.

At this point, we have established that all common characteristics will reside in the "Building" class, while additional characteristics specific to the school will be defined in the "School" class.

Similarly, we can create classes for "House" and "Shop," each containing their own specific characteristics. Now, I can create an object based on the "House" class and another based on the "Shop" class. If I run this, everything will process correctly.

When I need to add additional functionality specifically for the store, I will do so in the "Shop" class, not in the main class.

Let's now work with the "School" class, but you can apply similar actions to any other class. I will add a characteristic called "students," which represents the number of students. By default, I will set it to 0.

This characteristic is not needed in the "House" or "Shop" classes because the number of students only applies to schools. Therefore, it makes no sense to add this characteristic to the "Building" class.

Instead, we will place it in the subclass. I also want to add a constructor that will accept the number of students and the values for the parent class constructor.

To do this, I will use the "super" function to call the parent class constructor and pass the necessary parameters. This way, I don't need to assign these values again because they will be passed to the parent class constructor.

Now, I need to ensure that when creating a "School" object, I pass three parameters instead of two. Let's say I want to create a school with 100 students, a year of construction, and a city.

If I run this, everything will process correctly. However, we won't see any output regarding the number of students because we haven't included that in the "getInfo" method yet.

We can see that the data we receive is correctly passed to the parent class constructor, and it outputs the necessary information.

Inheritance allows us to create a subclass that inherits everything from the parent class. When we specify inheritance, we inherit all fields, constructors, and methods from the parent class.

Through objects created from the subclasses, we can access all fields, constructors, and methods from both the subclass and the parent class.

One more point: in Python, you cannot specify that one class has multiple parent classes. If I try to do that, it will raise an error. In contrast, languages like C++ allow multiple inheritance, which has been criticized for causing confusion among programmers.

In Python, you can only inherit from one class, as we have done here. However, a subclass can also have its own subclasses, which is perfectly fine.

Now, let's discuss another concept in OOP: polymorphism. This concept allows us to override methods defined in the parent class within the subclasses.

For example, the "getInfo" method works well in the "House" and "Shop" classes because they don't have any additional characteristics. If I call this method from an object of the "Shop" class, it will output all the relevant information.

However, for objects based on the "School" class, the "getInfo" method does not work as well because it only outputs the year and city, without mentioning the number of students.

Let's use polymorphism to override this method in the "School" class. To do this, we simply define a method with the same name, "getInfo," and we can also accept parameters if needed.

In this method, I will first call the parent class's "getInfo" method to output the initial information, and then I will add the additional information regarding the number of students.

Now, when I call this method from an object of the "School" class, it will automatically use the overridden method. If I call the same method from an object of the "Shop" class, it will use the method from the parent class.

Let's test this. When I call the method from the "School" object, it will output all the information, including the number of students. If I call it from the "Shop" object, it will only output the year and city.

You could also choose not to call the parent class's method, but I find it more logical to do so to avoid repeating code.

Thus, polymorphism allows you to take a method from the parent class and enhance it with new functionality in the subclass.

Finally, let's discuss encapsulation. This concept states that any fields in a class should be protected. In essence, encapsulation is about data protection.

Currently, our fields, constructors, and methods have no protection. For example, I can easily access a field and assign a new value without any errors.

Encapsulation tells us that access to such fields should be restricted, and they should only be accessible through methods or constructors within the class.

In Python, encapsulation is not very well implemented. I can add two underscores before a field name to make it somewhat private, but I can still access it if I know the name.

If I try to print this field directly, I will get an error because it is considered private. However, if I access it using its name with the underscores, it will work correctly.

So, encapsulation is an important concept that exists in many programming languages, but in Python, it is not strictly enforced.

In conclusion, our lesson is coming to an end. I hope you enjoyed it. If so, don't forget to subscribe to the channel and join our social media. All the links will be in the description of this video.

That's all for now. See you soon! Goodbye!