Python learning notes: object oriented programming! (come here first, there's no time to change recently!)

Posted by falled on Tue, 28 Sep 2021 05:42:09 +0200

1, Object oriented

The core of process oriented programming is process (pipeline thinking). Process is the step to solve the problem. Process oriented design is like carefully designing a pipeline and considering when to deal with what.
The advantage is that it greatly reduces the complexity of writing programs, and only needs to stack the code along the steps to be executed.
The disadvantage is: a set of pipeline or process is used to solve a problem, and the code affects the whole body.
Application scenario: once the scenario is completed, it rarely changes. Famous examples include Linux kernel, git, Apache HTTP Server, etc.

The core of object-oriented programming is the object (God thinking). To understand what the object is, we must regard ourselves as God. In God's eyes, all things in the world are objects, and those that do not exist can also be created.
The advantage is that it solves the scalability of the program. If you modify an object individually, it will be immediately reflected in the whole system. For example, it is easy to modify the characteristics and skills of a character parameter in the game.
Disadvantages: poor controllability, unable to predict the processing flow and results of problems to the process oriented programming pipeline. Once the object-oriented program starts, the problems are solved by the interaction between objects, and even God cannot predict the final results.

In python, object-oriented programming is not all.
Object oriented programming can make program maintenance and expansion easier, and can greatly improve program development efficiency. In addition, object-oriented program can make it easier for people to understand your code logic, so as to make team development more leisurely.

Know some nouns: class, object, instance, instantiation
Class: a class of things (people, dogs, tigers) with the same characteristics
Object / example: a specific thing (ah Hua next door, Wangcai downstairs)
Instantiation: the process of class - > object (this is not obvious in life, we will explain it later)

class

statement

def functionName(args):
     'Function document string'
      Function body 

'''
class Class name:
    'Class'
    Class body
'''

#Let's create a class
class Data:
    pass

attribute

class Person:   #Define a human being
    role = 'person'  #People's role attributes are people
    def walk(self):  #People can walk, that is, there is a way to walk
        print("person is walking...")

print(Person.role)  #View person's role properties
print(Person.walk)  #Reference the walking method of people. Note that this is not a call

Instantiation: the class name is instantiated with parentheses, which will be triggered automatically__ init__ Function can be used to customize its own characteristics for each instance

class Person:   #Define a human being
    role = 'person'  #People's role attributes are people
    def __init__(self,name):
        self.name = name  # Each character has its own nickname;
        
    def walk(self):  #People can walk, that is, there is a way to walk
        print("person is walking...")

print(Person.role)  #View person's role properties
print(Person.walk)  #Reference the walking method of people. Note that this is not a call

The process of instantiation is the process of class - > object

Originally, we had only one Person class. In this process, we generated an egg object with its own specific name, attack power and health value.

Syntax: object name = class name (parameter)

self

self: automatically pass the object / instance itself to the__ init__ For the first parameter, you can also give him an individual name, but normal people don't do that.
Because you changed, others don't know

Class attribute supplement

1:  Where are the properties of the class we defined? There are two ways to view
dir(Class name): It's a list of names
 Class name.__dict__:It's a dictionary, key Is the property name, value Attribute value

2:  Special class properties
 Class name.__name__# Class name (string)
Class name.__doc__# Class
 Class name.__base__# The first parent class of class (I will talk about inheritance)
Class name.__bases__# Class is a tuple composed of all parent classes (I will talk about inheritance)
Class name.__dict__# Dictionary properties of class
 Class name.__module__# The module where the class definition is located
 Class name.__class__# Class corresponding to instance (only in new class)

object

class Class name:
    def __init__(self,Parameter 1,Parameter 2):
        self.Property 1 of object = Parameter 1
        self.Properties of object 2 = Parameter 2

    def Method name(self):pass

    def Method name 2(self):pass

Object name = Class name(1,2)  #An object is an instance that represents a concrete thing
                  #Class name (): class name + parentheses is to instantiate a class, which is equivalent to calling__ init__ method
                  #Parameters are passed in parentheses. Parameters do not need to be passed to self. Other parameters correspond to the formal parameters in init one by one
                  #The result returns an object
 Object name.Property 1 of object   #To view the properties of an object, you can directly use the object name. Property name
 Object name.Method name()     #Call the method in the class directly with the object name. Method name ()

Exercise 1: output the following information at the terminal

Xiao Ming, 10 years old, male, went up the mountain to cut firewood
Xiao Ming, 10 years old, male, drives to the northeast
Xiao Ming, 10 years old, male, loves big health care best
Lao Li, 90, male, went up the mountain to cut firewood
Lao Li, 90, male, drove to the northeast
Lao Li, 90 years old, male, loves big health care best
Lao Zhang

Class namespace and object namespace

Creating a class will create a class namespace to store all the names defined in the class. These names are called class properties
Classes have two kinds of properties: static properties and dynamic properties
Static attributes are variables defined directly in a class
A dynamic attribute is a method defined in a class
The data properties of the class are shared to all objects

>>>id(egg.role)
4341594072
>>>id(Person.role)
4341594072
 The dynamic properties of a class are bound to all objects

>>>egg.attack
<bound method Person.attack of <__main__.Person object at 0x101285860>>
>>>Person.attack
<function Person.attack at 0x10127abf8> 

Creating an object / instance will create an object / instance namespace to store the name of the object / instance, which is called the attribute of the object / instance
In obj.name, you will first find name from obj's own namespace. If you can't find it, you will find it in the class. If the class can't find it, you will find the parent class... Finally, if you can't find it, you will throw an exception

2, Three characteristics of object-oriented: inheritance, polymorphism and encapsulation

inherit

Inheritance is a way to create a new class. In python, a new class can inherit one or more parent classes. The parent class can also be called a base class or superclass, and the new class is called a derived class or subclass
Class inheritance in python is divided into single inheritance and multi inheritance

class ParentClass1: #Define parent class
    pass

class ParentClass2: #Define parent class
    pass

class SubClass1(ParentClass1): #Single inheritance, the base class is ParentClass1, and the derived class is SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python supports multiple inheritance, separating multiple inherited classes with commas
    pass

Importance of inheritance

========================================PART ONE
 for example

  Cats can climb trees, eat, drink, pull and scatter

  Dogs can: watch the door, eat, drink, pull and sprinkle

If we want to create a class for cats and dogs respectively, we need to implement all their functions for cats and dogs. The pseudo code is as follows:
 
#Cats and dogs have a lot in common
class Cat:

    def climb up a tree(self):
        print 'climb up a tree'

    def eat(self):
        # do something

    def drink(self):
        # do something

    def PULL(self):
        # do something

    def Scatter(self):
        # do something

class dog:

    def Janitor(self):
        print 'Janitor'

    def eat(self):
        # do something

    def drink(self):
        # do something

    def PULL(self):
        # do something

    def Scatter(self):
        # do something

===================================PART TWO
 It is not difficult to see from the above code that eating, drinking, pulling and scattering are the functions of both cats and dogs, but we have written them twice in the cat and dog classes respectively. If the idea of inheritance is used, the implementation is as follows:

  Animals: eat, drink, pull and sprinkle

     Cat: climbing trees (cats inherit animal functions)

     Dog: watchdog (dog inherits animal function)

The pseudo code is as follows:
class animal:

    def eat(self):
        # do something

    def drink(self):
        # do something

    def PULL(self):
        # do something

    def Scatter(self):
        # do something

# Write another class name in parentheses after the class, indicating that the current class inherits another class
class cat(animal): 

    def climb up a tree(self):
        print 'climb up a tree'

# Write another class name in parentheses after the class, indicating that the current class inherits another class
class dog(animal): 

     def Janitor(self):
        print 'Janitor'

================================PART THREE
#Inherited code implementation
class Animal:

    def eat(self):
        print("%s eat " %self.name)

    def drink(self):
        print ("%s drink " %self.name)

    def shit(self):
        print ("%s PULL " %self.name)

    def pee(self):
        print ("%s Scatter " %self.name)


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = 'cat'

    def climb up a tree(self):
        print 'climb up a tree'

class Dog(Animal):

    def __init__(self, name):
        self.name = name
        self.breed='dog'
  
    def Janitor(self):
        print 'Janitor'

# ######### implement #########

c1 = Cat('Xiaobai's little black cat')
c1.eat()

c2 = Cat('Little black little white cat')
c2.drink()

d1 = Dog('Fat man's little thin dog')
d1.eat()

So much inheritance?

Can I inherit multiple classes
If the inherited multiple classes have the same function in each class, which one will be used?
1. Python classes can inherit multiple classes, while Java and C # can only inherit one class
2. If a Python class inherits multiple classes, there are two ways to find methods: depth first and breadth first

When the class is a classic class, in the case of multiple inheritance, it will be searched according to the depth first method
When the class is a new class, in the case of multiple inheritance, it will be searched according to the breadth first method
The classic class and the new class can be seen literally, one old and one new. The new class must contain the following functions, which is also the recommended writing method. If the writing method is distinguished, if the current class or parent class inherits the object class, then the class is a new class, otherwise it is a classic class.

class D:

    def bar(self):
        print 'D.bar'

class C(D):

    def bar(self):
        print 'C.bar'

class B(D):

    def bar(self):
        print 'B.bar'

class A(B, C):

    def bar(self):
        print 'A.bar'

a = A()
# When executing the bar method
# First, search in class A. if it is not found in class A, continue to search in class B. if it is not found in class B, continue to search in class D. if it is not found in class D, continue to search in class C. if it is still not found, an error is reported
# Therefore, the search order is: a -- > B -- > D -- > C
# In the above search method, once found, the search process will be interrupted immediately, and the search will not continue
a.bar()

Classic class multi inheritance
class D(object):

    def bar(self):
        print 'D.bar'

class C(D):

    def bar(self):
        print 'C.bar'

class B(D):

    def bar(self):
        print 'B.bar'

class A(B, C):

    def bar(self):
        print 'A.bar'

a = A()
# When executing the bar method
# First, search in class A. if it is not found in class A, continue to search in class B. if it is not found in class B, continue to search in class C. if it is not found in class C, continue to search in class D. if it is still not found, an error will be reported
# Therefore, the search order is: a -- > B -- > C -- > D
# In the above search method, once found, the search process will be interrupted immediately, and the search will not continue
a.bar()

New class multi inheritance

polymorphic

Python does not support polymorphic writing in strongly typed languages such as Java and C#, but it is native polymorphic. Python advocates "duck type".

class F1:
    pass
    
class S1(F1):

    def show(self):
        print 'S1.show'

class S2(F1):

    def show(self):
        print 'S2.show'

# Because in Java or C#When defining a function parameter in, you must specify the type of the parameter
# In order to enable Func function to execute both the show method of S1 object and the show method of S2 object, a parent class of S1 and S2 classes is defined
# The parameters actually passed in are S1 object and S2 object
def Func(F1 obj):
    """Func Function needs to receive a F1 Type or F1 Type of subclass"""
    
    print obj.show()
    
s1_obj = S1()
Func(s1_obj) # Pass in S1 class object S1 in Func function_ Obj, execute the show method of S1. Result: S1.show

s2_obj = S2()
Func(s2_obj) # Pass in the object Ss of the Ss class in the Func function_ Obj, execute the show method of Ss, and the result is S2.show

Python Pseudo code implementation Java or C#Polymorphism of
class F1:
    pass

class S1(F1):

    def show(self):
        print 'S1.show'

class S2(F1):

    def show(self):
        print 'S2.show'

def Func(obj):
    print obj.show()

s1_obj = S1()
Func(s1_obj) 

s2_obj = S2()
Func(s2_obj) 

Python ""Duck type"

encapsulation

Hide the properties and implementation details of the object, and only provide public access.

[benefits]

  1. Isolate changes;
  2. Easy to use;
  3. Improve reusability;
  4. Improve safety;

[packaging principle]
1. Hide all contents that do not need to be provided externally;
2. Hide all attributes and provide public methods to access them.

1. Abstract class and interface class

Like java, python also has the concept of abstract class, but it also needs to be implemented with the help of modules. Abstract class is a special class. Its particularity is that it can only be inherited and cannot be instantiated

Why abstract classes
If a class extracts the same content from a pile of objects, then an abstract class extracts the same content from a pile of classes, including data attributes and function attributes.
For example, we have banana class, apple class and peach class. The same content extracted from these classes is the abstract class of fruit. When you eat fruit, you either eat a specific banana or a specific peach...... You can never eat something called fruit.

From a design perspective, if a class is abstracted from a real object, then the abstract class is based on class abstraction.
From the implementation point of view, the difference between abstract classes and ordinary classes is that there are abstract methods in abstract classes. This class can not be instantiated, but can only be inherited, and subclasses must implement abstract methods. This is a bit similar to the interface, but it is actually different. The answer will be revealed soon

Interface class

Inheritance serves two purposes:

1: Inherit the methods of the base class and make your own changes or extensions (code reuse)
2: Declare that a subclass is compatible with a base class and define an Interface class Interface. Some Interface names (i.e. function names) are defined in the Interface class and do not implement the functions of the Interface. The subclass inherits the Interface class and implements the functions in the Interface

1. Multiple inheritance
In the process of inheriting abstract classes, we should try to avoid multiple inheritance;
When inheriting interfaces, we encourage you to inherit more interfaces
Interface isolation principle:
Use multiple specialized interfaces instead of a single general interface. That is, the client should not rely on interfaces that are not needed.

2. Implementation of the method
In abstract classes, we can make basic implementations of some abstract methods;
In the interface class, any method is only a specification, and the specific functions need to be implemented by subclasses

ps: combination

Object oriented composite usage
In addition to inheritance, there is another important way of software reuse, that is, composition
Composition refers to taking objects of another class as data attributes in one class, which is called class composition

class Person:

    def __init__(self,nickname,sex,hp,ad):
        self.nickname = nickname
        self.sex = sex
        self.hp = hp
        self.ad = ad

    def attack(self,p1):
        p1.hp -= self.ad
        print('%s Attacked%s,%s Remaining%s Blood volume'%(self.nickname,p1.nickname,p1.nickname,p1.hp))

    def weapon_attack(self,wea):
        # Weapon objects are encapsulated into human objects as an attribute. It is called composition
        self.weapon = wea

class Weapon:

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

    def Aux_attack(self,p,p1):
        p1.hp -= self.att
        print('%s utilize%s Yes%s%s Dripping blood,%s Remaining%s Dripping blood' %(p.nickname,self.name,p1.nickname,self.att,p1.nickname,p1.hp))

# alex = Person('alex ',' male ', 100,20)
# barry = Person('taibai ',' male ', 200,50)
# axe = Weapon('axe ', 30)
# barry.weapon_attack(axe)
# barry.weapon.Aux_attack(barry,alex)

# axe.Aux_attack(alex)
# alex.attack(barry)
# alex.attack(barry)

A ring consists of two circles. The area of the ring is the area of the outer circle minus the area of the inner circle. The circumference of the ring is the circumference of the inner circle plus the circumference of the outer circle.
At this time, we first implement a circle class to calculate the circumference and area of a circle. Then, in the "ring class", combine instances of circles as their own properties

from math import pi

class Circle:
    '''
    Defines a circular class;
    Provide calculated area(area)And perimeter(perimeter)Method of
    '''
    def __init__(self,radius):
        self.radius = radius

    def area(self):
         return pi * self.radius * self.radius

    def perimeter(self):
        return 2 * pi *self.radius


circle =  Circle(10) #Instantiate a circle
area1 = circle.area() #Calculate circle area
per1 = circle.perimeter() #Calculate circumference of circle
print(area1,per1) #Print circle area and perimeter

class Ring:
    '''
    Defines a torus class
    Method for providing the area and perimeter of a ring
    '''
    def __init__(self,radius_outside,radius_inside):
        self.outsid_circle = Circle(radius_outside)
        self.inside_circle = Circle(radius_inside)

    def area(self):
        return self.outsid_circle.area() - self.inside_circle.area()

    def perimeter(self):
        return  self.outsid_circle.perimeter() + self.inside_circle.perimeter()


ring = Ring(10,5) #Instantiate a ring
print(ring.perimeter()) #Calculate the circumference of the ring
print(ring.area()) #Calculate the area of the ring

The relationship between classes and combined classes is established in the way of composition. It is a kind of "yes" relationship. For example, professors have birthdays and teach python courses

class BirthDate:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

class Couse:
    def __init__(self,name,price,period):
        self.name=name
        self.price=price
        self.period=period

class Teacher:
    def __init__(self,name,gender,birth,course):
        self.name=name 
        self.gender=gender
        self.birth=birth
        self.course=course
    def teach(self): 
        print('teaching')
p1=Teacher('egon','male', 
            BirthDate('1995','1','27'), 
            Couse('python','28000','4 months')
           ) 

print(p1.birth.year,p1.birth.month,p1.birth.day) 

print(p1.course.name,p1.course.price,p1.course.period)
''' 
Operation results: 
1 27 
python 28000 4 months 
'''

When there are significant differences between classes, and the smaller class is the component required by the larger class, it is better to use composition

2. Private variables and methods

In python, the attribute is hidden (set to private) by starting with a double underscore

#In fact, this is just a deformation operation
#All double underlined names in the class, such as__ x will automatically become:_ Class name__ Form of x:

class A:
    __N=0 #The data attributes of a class should be shared, but grammatically, the data attributes of a class can be set to private, such as__ N. Will deform into_ A__N
    def __init__(self):
        self.__X=10 #Deform to self_ A__ X
    def __foo(self): #Deformation as_ A__foo
        print('from A')
    def bar(self):
        self.__foo() #It can only be passed inside a class__ foo form access to

#A._A__N is accessible, that is, this operation is not strictly restricting external access, but just a deformation in the grammatical sense

Features of this automatic deformation:

1. Defined in class__ X can only be used internally, such as self__ x. The reference is the result of deformation.
2. This deformation is actually aimed at the external deformation, which cannot be passed externally__ The name x is accessible.
3. Defined in subclass__ X does not override the definition of the parent class__ x. Because the subclass becomes:_ Subclass name__ x. The parent class changes into:_ Parent class name__ x. That is, when the attribute at the beginning of the double sliding line is inherited to the subclass, the subclass cannot be overwritten.

The problems needing attention in this deformation are:
1. This mechanism does not really restrict us from directly accessing attributes from the outside. We can spell the name after knowing the class name and attribute name:_ Class name__ Property, and then you can access it, such as a_ A__ N
2. The deformation process only takes effect inside the class. The assignment operation after definition will not deform
In inheritance, if the parent class does not want the child class to override its own method, it can define the method as private

#Normal condition
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B
 
#Define FA as private, i.e__ fa
>>> class A:
...     def __fa(self): #When defined, it deforms into_ A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #It will only be subject to its own class, that is, call_ A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

3. Packaging and expansion

Encapsulation is to clearly distinguish the inside and outside, so that the class implementer can modify the things in the encapsulation without affecting the code of the external caller; External users only know one interface (function). As long as the interface (function) name and parameters remain unchanged, the user's code never needs to be changed. This provides a good basis for cooperation -- in other words, code changes are not a concern as long as the basic interface convention remains unchanged.

#Class designer
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #The external interface hides the internal implementation details. At this time, what we want is the area
        return self.__width * self.__length

#User
>>> r1=Room('bedroom','egon',20,20,20)
>>> r1.tell_area() #User call interface tell_area

#The designer of the class easily extends the function, and the user of the class does not need to change his code at all
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #The external interface hides the internal implementation. At this time, what we want is the volume. The internal logic has changed. We only need to repair the following line to achieve a very simple implementation. Moreover, the external call is not aware of it. We still use this method, but the function has changed
        return self.__width * self.__length * self.__high

#For still using tell_area interface people can use new functions without changing their own code
>>> r1.tell_area()

Topics: Python OOP