## combination

### 1. What is a combination?

Composition refers to the attributes in one object, which is another object.

Inheritance: a relationship between a class and a class, a relationship of what is what, the subclass is the subordinate relationship of the parent class. Combination: The relationship between objects and objects, a relationship between what is and what, one object owns another object. Combination advantages: decoupling between classes and high scalability. Combination disadvantages: high writing complexity. Inheritance advantages: low writing complexity. Inheritance disadvantages: high coupling.

```class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

class Teacher(People):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)

class Student(People):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)

class Date:
def __init__(self, year, mouth, day):
self.year = year
self.mouth = mouth
self.day = day

def tell_birth(self):
print(f'''
=== Date of Birth ===
Year: {self.year}
Month: {self.mouth}
Day: {self.day}
''')

tea1 = Teacher('tank', 17,'male')
date_obj = Date(2002, 1, 1)
tea1.date = date_obj #(combination) Assign the date object to the date attribute of the tea1 object
tea1.date.tell_birth()
'''=== Date of Birth ===
Year: 2002
Month: 1
Day: 1'''```

### 3. Combined exercises

Course selection system requirements: 1. Students, teachers, students and teachers have course attributes, and each course is an object. Course: course name, course period, course price 2. Both students and teachers have the function of choosing courses , There is also the function of printing all courses.

```class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

# Add each course
self.course_list.append(course_name) # Each course_name is a course object

def tell_all_course(self): # Combine, assign each course object to the tell_all_course method
for course_obj in self.course_list:
# Call each course object to view the method of course information
course_obj.tell_course_info()

class Teacher(People):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)
self.course_list = [] # Put each instantiated course object in the list

class Student(People):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)
self.course_list = []

class Course: # Course class
def __init__(self, course_name, course_period, course_price):
self.course_name = course_name
self.course_period = course_period
self.course_price = course_price

def tell_course_info(self):
print(f'''
Course name: {self.course_name}
Course period: {self.course_period}
Course price: {self.course_price}
''')

teal = Teacher('Lilei', 18,'male')
python_obj = Course('python', 6, 20000)
linux_obj = Course('linux', 6, 10000)

teal.tell_all_course()
''' Course name: python
Course period: 6
Course price: 20000

Course name: linux
Course period: 6
Course price: 10000'''```

## Encapsulation

### 1. What is encapsulation

Encapsulation is the core of object-oriented. Sealing: For example, to seal a bag: For example, to pack a bunch of things into a bag. Encapsulation refers to encapsulating a bunch of attributes (features and skills) into an object. Metaphor: An object is like a bag with a bunch of things inside the bag. Property object can get properties in the way of'.'

### 2. Why encapsulate

(1. Encapsulate data attributes: hide the data so that the users of the class cannot directly manipulate the data attributes. The designer of the class needs to open up an interface inside the class, so that the user of the class can indirectly manipulate the data through the interface, and the design of the class The user can add logic to the interface arbitrarily to strictly control the operation of the attribute by the user of the class.

```class People:
def __init__(self,name,age):
self.__name = name
self.__age = age
def tell_info(self):
print('<%s:%s>'%(self.__name,self.__age))

def set_info(self,name,age):#Limit the type of data entered by the user
if type(name) is not str:
raise TypeError('User name must be of type str')
if type(age) is not int:
raise TypeError('Age must be int')

self.__name = name
self.__age = age
p = People('xiaohua','18')
p.tell_info()
p.set_info('xiaolei',17)
p.tell_info()
'''<xiaohua:18>
<xiaolei:17>'''```

(2. The purpose of encapsulation is to facilitate access. You can obtain attributes through the object'.'attributes, isolate the complexity to simplify complex operations

```class ATM:
def __card(self):
print('Insert card')

def __auth(self):
print('User authentication')
def __input(self):
print('Enter the withdrawal amount')
def __print_bill(self):
print('Print bill')
def __take_money(self):
print('Withdrawal')

def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()

a = ATM()
a.withdraw()
'''
Card
User Authentication
Enter the withdrawal amount
Print bill
Withdrawal
'''```

### 3. How to package

Features: Variables-"Data Attribute Skills: Functions-"Methods Attributes are inside the class, defining a bunch of attributes (features and skills) through objects. Attribute = attribute value C language also has the idea of ​​surface object programming

### 4. What is the access restriction mechanism

Defined inside the class, all data attributes and methods beginning with __ will be hidden by python, and the internal attributes of the class (starting with __) cannot be directly accessed from the outside, but can be directly accessed internally. (The examples in 3. are all encapsulated in a way of restricting access) The purpose of the access restriction mechanism: to hide a bunch of private properties and properties that cannot be easily accessed by the outside, and not be directly called by the outside. Benefits: The logic of acquiring important data is more rigorous, thereby ensuring data security.

```class Foo:
__n = 1
def __init__(self,name):
self.__name = name
def __f1(self):#_Foo__f1 (just change the attribute name __f1 to _Foo__f1, it can be called when using _Foo__f1 to call the method)
print('f1')
def f2(self):
self.__f1() #self._Foo__f1()
print(self.__name)#self._Foo__name
print(self.__n)#self._Foo__n
obj = Foo('lilei')
obj.f2()
#print(obj.__name)
print(obj.__dict__)
print(Foo.__dict__)
'''
f1
lilei
1
{'_Foo__name':'lilei'}
{'__module__':'__main__','_Foo__n': 1,'__init__': <function Foo.__init__ at 0x00000252B98E6048>,'_Foo__f1': <function Foo.__f1 at 0x00000252B98E66A8>,'f2': <function Foo.f2 at 0x00000252C09A4048>,'__dict__': <attribute'__dict__' of'Foo' objects>,'__weakref__': <attribute'__weakref__' of'Foo' objects>,'__doc__': None}

Process finished with exit code 0

'''```

This hidden feature:

1. It's just a grammatical deformation, and the attribute starting with __ will be defined as its own class name __ attribute name.
2. This transformation only occurs once in the class definition stage, and the new attributes starting with __ after the class definition stage will not be transformed.
3. Hidden is external and internal, because the attributes in the class are deformed during the class definition phase, so you can access the internal properties of the class.
4. If the parent class does not want the subclass to cover its own method of the same name, the method can be defined as private,

### 5. Interface

Privacy attributes can be used to encapsulate an interface, do business logic processing in the interface, and then return the data to the caller. Note: There is no mandatory restriction of attribute access in python. The attribute at the beginning of __ within the class is just a modification of the attribute name.

```class ATM:
def __card(self):
print('Insert card')

def __auth(self):
print('User authentication')
def __input(self):
print('Enter the withdrawal amount')
def __print_bill(self):
print('Print bill')
def __take_money(self):
print('Withdrawal')

def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()

a = ATM()
a.withdraw()
'''
Card
User Authentication
Enter the withdrawal amount
Print bill
Withdrawal
'''```

## property (understand)

1. What is property (attribute)

Python's built-in decorator is mainly used for methods inside the class.

2. Why use property

Purpose of use: Change the method (def method name ()) inside the class to (def method name) When an object calls a method, turn the object. method () into an object. method (looks like an ordinary data attribute )

3. How to use property

@property

The definition and call of property attributes should pay attention to the following points:

1. When defining, add @property decorator to the instance method; and there is only one self parameter
2. When calling, no parentheses are required

note:

• The properties in the classic class have only one access method, which corresponds to the method modified by @property
• There are three ways to access the properties in the new-style class, and they correspond to three methods modified by @property, @方法名.setter, and @方法名.deleter

Since there are three access methods in the new-style class, we can define the three methods to access the same attribute according to the access characteristics of their several attributes: get, modify, delete

Example: Calculate the human body's bmi: bmi value = weight/(height * height)

```class People:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height

@property
def bmi(self):
return self.weight/(self.height * self.height)
# Use a decorator to decorate get_name, then an attribute called get_name will be automatically added, and when the value of get_n is called, the decorated method is called
@property
def get_name(self):
return self.name
@get_name.setter## Use decorator to decorate get_name, when set value to get_name, call the decorated method
def set_name(self,val):
self.name = val
@get_name.deleter
def del_name(self):
del self.name

P = People('xiaohua',120,170)
print(P.get_name)
print(P.bmi)# The area can be accessed the same as the data attribute, which will trigger the execution of a function and dynamically calculate a value
del P.del_name
print(P.get_name)```

There are four parameters in the property method

1. The first parameter is the name of the method, which automatically triggers the execution of the method when the object. property is called
2. The second parameter is the name of the method, the object is called. The method is automatically triggered when the attribute = XXX
3. The third parameter is the name of the method, which automatically triggers the execution of the method when calling the del object.
4. The fourth parameter is a string, calling object.attribute.__doc__, this parameter is the description of the attribute

Since the creation of the property attribute by the class attribute method has three access methods, we can define the three methods respectively to the same attribute according to the access characteristics of their several attributes: get, modify, delete

In summary:

• There are two ways to define property attributes, namely [Decorator] and [Class Attribute], and the [Decorator] method is different for classic and new-style classes.
• By using the property attribute, the caller can simplify the process of obtaining data

## Polymorphism:

### 1. What is polymorphism

Polymorphism: Multiple forms of the same thing.

### 2. The purpose of polymorphism:

Polymorphism is also called polymorphism, and inheritance in programs is the manifestation of polymorphism. The purpose of polymorphism is to allow multiple different types of objects to use the same function (method) to call the method parent class of the same name: define a set of unified standards. Subcategory: Follow the unified standard of the parent category. The ultimate goal of polymorphism: to unify the standard of subclass definition methods (unified writing specifications), in order to make it easier for users to call methods of the same function

```class Animal:
# Eat
def eat(self):
pass

# Drink
def drink(self):
pass

# Call
def speak(self):
pass
# Pig
class Pig(Animal):

# Eat
def eat(self):
print('Pigs are eating')
pass

# Drink
def drink(self):
pass

def speak(self):
print('Hmm~~~')

# Cat
class Cat:
# Eat
def eat(self):
print('The cat is eating')
pass
# Drink
def drink(self):
pass

def speak(self):
print('Meow meow~~')
# dog
class Dog:
# Eat
def eat(self):
print('Dog is eating')
pass

# Drink
def drink(self):
pass

def speak(self):
print('Wow~~~')

# Correct textbook
pig = Pig()
cat = Cat()
dog = Dog()

pig.speak()
cat.speak()
dog.speak()```

### 3. How to achieve:

——Inheritance note: In python, it is not mandatory that subclasses must follow the standards of the parent class, so there is an abstract class.

### Abstract class:

1. What is: abc module abstract_class
2. Purpose and function of use: It is mandatory that subclasses must follow the standards of the parent class.
3. How to use: import abc
4. When using abc, you should pay attention that the method of adding abc decorator under the parent class must be defined in the subclass and must use the same method name, otherwise an error will be reported: Can't instantiate abstract class subclass name with abstract methods method name, as long as the subclass There are methods for mandatory definition of the parent class, and other methods can be defined at will without error.
```import abc

class Animal(metaclass=abc.ABCMeta):

# Eat
@abc.abstractmethod
def eat(self):
pass

# Drink
@abc.abstractmethod
def drink(self):
pass

# Call
@abc.abstractmethod
def speak(self):
pass

# Pig
class Pig(Animal):
# Eat
def eat(self):
print('Pigs are eating')
pass

# Drink
def drink(self):
pass

def speak(self):
print('Hmm~~~')

# Derive
def run(self):
pass

pig = Pig()```

## Duck type

Python does not respect mandatory, but the respected classes follow the duck type.

### What is a duck type

Duck type: Without knowing what the current object is, what it looks like is what it looks like. The characteristics of the duck type: They all follow the same definition standard and do not force the use of abstract classes, which reduces coupling and improves the scalability of the program. In this way, the scalability of the program will be higher.

```# Pig
class Pig:
# Eat
def eat(self):
print('Pigs are eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Hmm~~~')

# Cat
class Cat:
# Eat
def eat(self):
print('The cat is eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Meow meow~~')

# dog
class Dog:
# Eat
def eat(self):
print('Dog is eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Wow~~~')```

When the developer obeys the duck type by default, there is no need to use the parent class plus abstract class method to force the developer to obey the rules, so the coupling degree of the code is reduced, and the code scalability is higher.

### Comparison of inheritance and duck type:

Inheritance: too high coupling, poor scalability of the program

Duck type: low coupling, strong program scalability

```class Pig:
# Eat
def eat(self):
print('Pigs are eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Hmm~~~')

# Cat
class Cat:
# Eat
def eat(self):
print('The cat is eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Meow meow~~')

# dog
class Dog:
# Eat
def eat(self):
print('Dog is eating')
pass
# Drink
def drink(self):
pass
def speak(self):
print('Wow~~~')

dog = Dog()
cat = Cat()
pig = Pig()

def BARK(animal):#When all classes are defined in accordance with the duck type, it is more convenient for objects to call attribute methods
animal.speak()

BARK(dog)
BARK(cat)
BARK(pig)```

## summary

1. Combination:-What is combination refers to the properties in one object, which is another object.-Why use combination is the same as inheritance, in order to reduce code redundancy. 2. Encapsulation:-What is encapsulation? Encapsulation It refers to encapsulating a bunch of attributes (features and skills) into an object. The purpose of storing data is to retrieve the attributes, and the object can obtain attributes in the form of ".".

```    -Why encapsulate?
For the purpose of encapsulation, for convenient access, properties can be obtained through objects and properties.```

3. Access restriction mechanism:-What is the access restriction mechanism? Defined inside the class, all data attributes and method attributes beginning with __ will be hidden inside python, so that the outside cannot "directly" access the beginning of __ inside the class Properties.

```-The purpose of the access restriction mechanism?
A bunch of private attributes and attributes that cannot be easily accessed by the outside can be hidden and not directly called by the outside.   ```

4.property:-What is the built-in decorator of property python, which is mainly used for methods inside the class.

```-Why use property
When an object calls a method, turn the object.method() into an object.method (it looks like a normal data attribute)
obj.bmi() == obj.bmi

-How to use property
@property
Methods inside the def class (self):```

5. Polymorphism:-What is polymorphism? Polymorphism refers to multiple forms of the same thing.

```-The purpose of polymorphism:
The purpose of polymorphism is to allow multiple different types of objects to call the method name of the same name while using the same function.
Parent category: Define a set of unified standards.
Sub-category: Follow the unified standard of the parent category.

- How to achieve:
-Inherit the parent class
-Inherit the abstract class
-Duck type```

6. The purpose of the abstract class: to force the subclass to follow the set of standards of the parent class.

7. Duck type:-What is a duck type? Without knowing what the current object is, but you look like a duck, then you are a duck type.-Inheritance: The coupling is too high, and the scalability of the program is poor

```-Duck type:
Low coupling, strong scalability of the program```
Reference: https://cloud.tencent.com/developer/article/1553259 Combination, Packaging, Polymorphism-Cloud + Community-Tencent Cloud