This is the 16th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge

In fact, many knowledge points seem to be familiar to us, but we can’t be familiar with them any more, and some code has become a habit, because we are too familiar with them, and forget to ask why they are written like this, so take appropriate time to sort out some past or familiar knowledge, may have unexpected harvest

The Python language’s support for object orientation

OOP was such a popular design pattern that even sales managers used the term object oriented once or twice when talking to customers. In the last couple of years it’s been a bit overshadowed by FP(functional programming), but for the most part I still choose to model and organize my code in an object-oriented way. So what is object-oriented programming

What is object-oriented programming

Object-oriented programming is a programming paradigm that provides a way to structure programs, binding properties and behaviors to a single object. In other words, object-oriented programming is a way of modeling concrete, real-world things, such as cars, and the relationships between things, such as companies and employees, students and teachers, and so on.

Object-oriented programming is a programming paradigm that provides a way to structure programs, binding properties and behaviors to a single object. That is to define the data structure, the data structure reflects a thing, for example, the commodity is the name of the collection, is an abstract description of the commodity, with generality. A specific product is an instance, with attributes such as the name, specification, and price of the product. Then there is E-mail, whose properties include the list of recipients, the subject and the body, as well as actions such as attaching and sending.

OOP is not only a method of modeling real things, but also a method of mapping real things to object-oriented classes when designing programs. Object-oriented classes are data structures. The object of OOP is to organize code effectively and reasonably. Is the solution to how we implement multi-person development to effectively organize code, and that’s what I’ve learned about object-oriented so far.

What is procedural programming

OOP models real-world entities as software objects that have some data and behavior associated with them organized as objects. Another common programming paradigm is procedural programming, designing programs like cooking a delicious dish from a recipe and organizing code to complete a task according to a process.

The key takeaway is that objects are central to object-oriented programming in Python, not only representing data as programmatically, but also in the overall structure of the program.

Define classes in Python

Basic data structures like numbers, strings, and lists are designed with basic types to represent simple information, like a set of fruits for a course, or a favorite color, that can’t be represented with basic data types, and we need more complex data types to describe these things.

For example, you need to maintain a list of published courses. You need to store some basic information for each course, such as course title, difficulty level, and number of courses.

basic_machine_learning_tut = ["basic machine learning".'baisc'.12]
basic_python_tut = ["basic python".'baisc'.12]
deep_learning_tut = ["basic python".'advance'.6]
Copy the code

There are some problems with this representation

  • Difficult to manage and maintain when using referencesbasic_machine_learning_tut[0]We need to familiarize ourselves with which attribute of the course, the name of the course or the number of courses, corresponds to a list index of 0
  • Difficult to maintain, once a record has data missing data will occur data mismatches, with the result that the data is not obtained correctly.

The benefits of maintaining data with classes are readability and ease of maintenance

Class and instance

Classes are used to create user-defined data structures. Functions defined in a class are called methods. Methods are used to create an object based on the class. Methods can be used to manipulate data, such as defining how to get data and how to update data. Next, we’ll share how to define and use a class around the class. Class is an abstract description of things, is an abstraction of a class of things, such as students, employees and companies, we abstract these things according to the business, give a description, a bit similar to the generation of parts design drawings, which does not contain any actual data, of course, will also include some objects to share methods and data.

With a drawing, we can define an instance (object) based on the drawing. An object is a concrete data structure relative to a class.

How do you define a class in Python

class Tut:
    pass
Copy the code

When you define a class in Python, you use the class keyword to give the class its name. The class as a collection is usually an actual name with an uppercase first letter. A class can be named using a camel’s hump name.

Some of the attributes that all course objects must have can be defined in a method called.__init__(), which can be interpreted as a class constructor. Each time a new course object is created, __init__() initializes the object’s properties by assigning the object’s property values. That is,.__init__() initializes an instance of the class. The first argument to __init__() is always self followed by the other arguments.

class Tut:
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        
Copy the code

The attributes defined in __init__() are instance attributes, which vary from instance to instance. If a class attribute is defined outside of __init()__, the attribute defined at the class level is shared by all objects of the class.

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
Copy the code

Category = “Language Programming” Begins defining class-level attributes under the class definition statement. Class-level attributes must be given initial values. Category attributes are shared by objects instantiated by the class.

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        

basic_machine_learning_tut = Tut("basic machine learning".12)
print(basic_machine_learning_tut.category)
Copy the code

You can modify a class property on an instance, but changing a class property on an instance does not affect the value of the property on other objects of that class.

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        

basic_machine_learning_tut = Tut("basic machine learning".12)
print(basic_machine_learning_tut.category)#language programming

basic_machine_learning_tut.category = "change class attribiutes"
print(basic_machine_learning_tut.category)#change class attribiutes

basic_python_tut = Tut("basic python".12)
print(basic_python_tut.category)#language programming
Copy the code

How to instantiate an instance in Python

class Tut:
    pass

print(Tut()) #<__main__.Tut object at 0x1024b1a10>
Copy the code

Here instantiating a class object, like calling a method, instantiates an instance of Tut by adding a pair of parentheses to the class name and creating a new Tut object at 0x1024B1a10. The number string is a memory address indicating where the class object is stored in your computer’s memory.

a = Tut()
b = Tut()
print(a == b) #False
Copy the code

Each time a Tut object is instantiated, a new memory location is allocated for the object to hold. In this code, you create two new course objects and assign values to variables A and b. If a and b are equal using the == operator, the result is False. Although A and B are both instances of the course class, they represent two different objects because they are located in different memory locations.

Class and instance properties

In the following code, you’ll see how to define class and object properties in a class and any calls to these properties, but I won’t go into that because the code is easy to read, okay

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        

basic_machine_learning_tut = Tut("basic machine learning".12)
basic_python_tut = Tut("basic python".12)

print(f"class attributes category: {basic_machine_learning_tut.category}")
# class attributes category: language programming
print(f"instance attributes title :{basic_machine_learning_tut.title}")
# instance attributes title :basic machine learning
print(f"instance attributes lesson :{basic_machine_learning_tut.lesson}")
# instance attributes lesson :12
Copy the code

During instantiation, in addition to the self argument, which is assigned by the system, title· and Lesson need to be assigned.

class Tut:
    category = "language programming"
    def __init__(title,lesson) :
        # self.title = title
        # self.lesson = lesson
        title.lesson = lesson
        
a = Tut(12)
print(a.lesson)
Copy the code

Note that self cannot be omitted, and that the first argument name can be given a new name without self, as follows

class Tut:
    category = "language programming"
    def __init__(title,lesson,others) :
        # self.title = title
        # self.lesson = lesson
        title.lesson = lesson
        title.others = others
        
a = Tut(12."others")
print(a.lesson) # 12
print(a.others) #others
Copy the code

Method of instance

An instance method is a function defined in a class that can only be called from an instance of that class. As with.__init__(), the first argument to the instance method is always self.

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        
    def description(self) :
        return f"description: title {self.title}, lesson: {self.lesson}"


basic_machine_learning_tut = Tut("basic machine learning".12)
print(basic_machine_learning_tut.description())
Copy the code

In the Tut class above,.description() returns a string containing the course instance information. Of course, when writing your own class, there’s nothing wrong with defining a method that returns a string containing useful information about an instance of that class. However, doing so. Description () is not the most Pythonic way to do it.

print(basic_machine_learning_tut) #<__main__.Tut object at 0x10186b250>
Copy the code

When we print the instantiated object basic_machine_learning_tut, which returns information about the location of the object and the location of the memory address, let’s look at the output list object, as follows

tuts = ["basic_machine_learning_tut"."basic_python_tut"."deep_learning_tut"]
print(tuts)#['basic_machine_learning_tut', 'basic_python_tut', 'deep_learning_tut']
Copy the code

You can change the contents of the print object by defining a special instance method called.__str__().

class Tut:
    category = "language programming"
    def __init__(self,title,lesson) :
        self.title = title
        self.lesson = lesson
        
    def __str__(self) :
        return f"description: title {self.title}, lesson: {self.lesson}"
   
basic_machine_learning_tut = Tut("basic machine learning".12)
print(basic_machine_learning_tut)
Copy the code

Methods such as.__init__() and.__str__() are called dunder/magic methods, and usually these methods begin and end with a double underscore. There are many Dunder/Magic methods that you can use to customize classes in Python, but understanding dunder/ Magic methods is an important part of mastering object-oriented programming in Python.

Implement class inheritance in Python

The three main characteristics of object-oriented programming – encapsulation, inheritance, where inheritance is the process by which one class accepts the properties and methods of another class, and polymorphism. Inheritance has two meanings at once

  • Inheriting the methods of the base class and making their own changes and/or extensions mainly solves the problem of code reuse
  • Declaring that a subclass is compatible with a base class (or that the interface is fully compatible with the base class) eliminates the need for external callers to notice the difference

Superclass and subclass

class Developer:

    def __init__(self,name,age) :
        self.name = name
        self.age = age

    def intro(self,lang) :
        return f"my name is {self.name} can write {lang}"

    def __str__(self) :
        return f"my name is {self.name} and {self.age} years old"
Copy the code

Then let’s define a subclass of Developer. In Python, it’s very easy to inherit a class. You just put the name of the parent class in parentheses after the name of the class

class PythonDeveloper(Developer) :
    pass

class JavaDeveloper(Developer) :
    pass

class JavaScriptDeveloper(Developer) :
    pass
Copy the code

Even if we don’t define the class at all, mike, an object instantiating PythonDeveloper, has the properties and methods of its parent class because it inherits from class Developer.

mike = PythonDeveloper("mike".28)
print(mike) #my name is mike and 28 years old
print(mike.intro("python")) #my name is mike can write python
Copy the code

Next, we instantiate each of the three subclasses defined above that inherit from the parent class Developer

mike = PythonDeveloper("mike".28)
tony = JavaDeveloper("tony".32)
kerry = JavaScriptDeveloper("kerry".26)
Copy the code

Let’s take a look at the object that instantiates PythonDeveloper. Mike is of type PythonDeveloper and

print(isinstance(mike,Developer)) #True
print(type(mike)) #<class '__main__.PythonDeveloper'>
Copy the code
print(isinstance(mike,JavaScriptDeveloper)) #False
Copy the code

Extend the functionality of the parent class

Programmers who specialize in different languages have different INTRo methods. We want to define a class with a default value for the member language that categorize programmers by language. For example, PythonDeveloper’s Intro method language (lang) defaults to Python. So this is just a simple demonstration of how to extend the superclass method capability, and then this method intro with the same name as the superclass calls the superclass intro method, right

class PythonDeveloper(Developer) :
    def intro(self,lang='python') :
        return super().intro(lang)
Copy the code

In many cases we need to completely override the methods of the parent class, but in this case we also need to leave intro in the parent class so that any changes to the method of the parent class will affect the PythonDeveloper subclass. So the intro method in the subclass PythonDeveloper calls the intro method in the superclass Developer.

print(mike.intro()) #my name is mike can write python
Copy the code

One thing to remember about class inheritance is that changes to a parent class are automatically propagated to its children. Unless a subclass overwrites the property or method

Multiple inheritance in Python

Python also supports multiple inheritance, in which a subclass can inherit from multiple superclasses that do not necessarily inherit from each other. Let’s now see if a subclass can have multiple inheritance, which is not supported in some object-oriented languages. The following example may seem unreasonable, but just for demonstration purposes, two classes are defined: Employee and Developer.

Implement multiple inheritance

class Employee:
    def __init__(self,name,age) :
        self.name = name
        self.age = age

    def intro(self) :
        return f"my name is {self.name} and {self.age} year old"
    
    def salary(self) :
        return "salaray"

class Developer:
    def __init__(self,lang) :
        self.lang = lang

    def intro(self) :
        return f"I'm a developer and can code {self.lang}"
Copy the code

The Empoyee and Developer constructors take two arguments and one argument, respectively, and have intro. Multiple inheritance in Python is as simple as putting Employee and Developer in parentheses around the class name. Note that some of these two classes are sequential.

class ADeveloperEmployee(Employee,Developer) :
    pass

mike = ADeveloperEmployee("python")
print(mike.intro())
Copy the code

Here we define a class ADeveloperEmployee that inherits from Employee, Developer, and calls the first parent __init__ function by default to initialize class instance properties without defining the initialization function __init__, So when the first parent class is Employee, we need to pass two parameters to instantiate it, and if we pass one of the following parameters, the system will throw an exception telling us that we need two parameters.

Traceback (most recent call last):
  File "demo_03.py", line 19.in <module>
    mike = ADeveloperEmployee("python")
TypeError: __init__() missing 1 required positional argument: 'age'
Copy the code

if

class ADeveloperEmployee(Developer,Employee) :
    pass

mike = ADeveloperEmployee("python")
print(mike.intro())
Copy the code

Although instantiating ADeveloperEmployee does not output an Employee method, mike is also an Employee and Developer

print(isinstance(mike,Employee)) #True
print(isinstance(mike,Developer)) #True
Copy the code
class Employee:
    def __init__(self,name,age) :
        print("employee init()")
        self.name = name
        self.age = age

    def intro(self) :
        return f"my name is {self.name} and {self.age} year old"
    
    def salary(self) :
        return "salaray"

class Developer:
    def __init__(self,lang) :
        print("developer init()")
        self.lang = lang

    def intro(self) :
        return f"I'm a developer and can code {self.lang}"

class ADeveloperEmployee(Developer,Employee) :
    pass
Copy the code
mike = ADeveloperEmployee("python") #developer init()
print(mike.salary()) #salary
Copy the code

MRO(Method parsing order)

print(ADeveloperEmployee.__mro__)
Copy the code

The method resolution order (or MRO) tells Python how to search for inherited methods. It’s kind of like a Javascript prototype chain. Each class has a.__mro__ attribute that checks the order in which methods are resolved.

(<class '__main__.ADeveloperEmployee'>, <class '__main__.Developer'>, <class '__main__.Employee'>, <class 'object'>)
Copy the code

When mike’s intro method is called, Developer’s intro is called first along the parse order. If not, Developer’s intro is called directly. If not, Developer’s intro is called along the parse order to see if any other parent class has the method.