10. Object Oriented Python

Object Oriented Programming-Object Oriented Programming, OOP for short, is a programming idea. OOP regards the object as the basic unit of the program, and an object contains data and functions to manipulate the data.

Object-oriented initial recognition

Process Oriented vs Functional Programming#####

Machine-oriented

Abstracted into machine instructions, the machine is easy to understand
Represents: assembly language

Process-oriented

Do one thing, set out a step, what to do in the first step, what to do in the second step, if situation A occurs, what to do, and if situation B occurs, what to do
The problem is small in scale and can be handled step by step
Representative: C language.

# Process-oriented programming measures the number of elements of the object.
s1 ='fjdsklafsjda'
count =0for i in s1:
 count +=1

l1 =[1,2,3,4]
count =0for i in l1:
 count +=1

` Compared with process-oriented programming, functional programming has two most obvious characteristics.

# 1. Reduce code reusability
# 2. Enhance the readability of the code
Functional programming vs object-oriented programming
# Functional programming

# auth authentication related
def login():
 pass

def regisgter():
 pass

# account account related
def func1():
 pass

def func2():
 pass

# Shopping cart related
def shopping(username,money):
 pass
def check_paidgoods(username,money):
 pass
def check_unpaidgoods(username,money):
 pass
def save(username,money):
 pass
# Object-Oriented Programming
classLoginHandler:
 def login(self):
  pass

 def regisgter(self):
  pass

classAccount:
 def func1(self):
  pass

 def func2(self):
  pass

classShoppingCar:
 def shopping(username,money):
  pass
 def check_paidgoods(username,money):
  pass
 def check_unpaidgoods(username,money):
  pass
 def save(username,money):
  pass

Through comparison, we can see the first advantage of object-oriented

# Object-oriented programming: a collection of similar functions,Make your code clearer and more rational.

# Before talking about the second advantage, let's take a look at what is object-oriented.

# The core of object-oriented programming is the object (God-like thinking). To understand what an object is, you must regard yourself as a god. In the eyes of God, everything that exists in the world is an object, and those that don't exist can be created.

# What is a class? What is an object?

# Class: A class of things with the same properties and functions.

# Object: It is the concrete manifestation of the class.

# Be specific: first explain what is ⻋?There is a wheel,Directional plate,With engine,What will run is ⻋.it is good.Explaining a.What is ⼈.Have a name,age,Hobby,The one who can sing, dance and think is one.So in a broad sense, people are types: but in my car, you are an object.

# Cats are a kind of big tangerines raised in your house.

# Dogs are of the first type, and the Erha who is raised next door is the target.

# Face-to-object thinking,To create objects by yourself.Create a scene by yourself.You are the God in the object world.Do you want to let it go.Do you want anyone to be able to do it?

Let's talk about the second advantage: object-oriented, to have a God's perspective to see the problem, the class is actually a public template (factory), the object is instantiated from the specific template (slowly understand).

Functional programming

def func(s):
 count =0for i in s:
  count +=1return count
func('fdsafdsa')func([1,2,3,4])

Object Oriented Programming

With the expansion of the scale of the problems that computers need to solve, the situation becomes more and more complicated. It requires a lot of people and many departments to coordinate. Process-oriented programming is too unsuitable.
Representative: C++, JAVA, Python, etc.

Object Oriented####

What is object-oriented?

A methodology for understanding and analyzing the world, abstracting everything into categories.

Class

A class is an abstract concept, an abstraction of everything, and a collection of common characteristics of a class of things.
To describe a class in computer language is a collection of attributes and methods.

Object instance, object

An object is a concrete representation of a class, an entity.
For each of us, this individual is a different entity of abstract human beings.

Objects and classes

# Class: Type of object=>digital
# Have the same characteristics and behavior set

# Object: the concrete performance of the class=>Number 10
# The instantiation of a class is an individual with characteristics and behaviors that actually exist (each object is unique)

# Example1
# You eat fish
# You are the object;Fish is also an object; eating is action
# You are a specific person and a specific object. You belong to humans, humans are an abstract concept,
# Is an abstraction of countless concrete individuals.And is also the specific object, which is the specific fish you eat.
# This fish belongs to fish, it is a concept abstracted by countless fish.

# eat,是动作,也是操作,也是方法,这个eat是你的动作,也就是人类具有的方法,
# If the other way round, fish can eat people, and eating is the action of fish.
# Eating is an action that many animals have. Humans and fishes belong to the animal category, and the animal category is an abstract concept,
# Animals all eat, but they eat differently.
# You drive a car. This car is also a specific object (instance) of the car class. Driving this action is not possessed by fish, but is a method possessed by humans..

# Attributes,He is an abstraction of the state of an object, described by a data structure.
# Operation, he is an abstraction of object behavior, described by the name of the operation and the method to implement the operation.

# Everyone has information such as name, height, weight, etc. These information are personal attributes, but this information cannot be stored in humans.
# Because it is an abstract concept and cannot retain specific values.
# The human instance is a specific person, and these specific attributes can also be stored, and different people can have different attributes..

# philosophy
# Everything is an object
# Object is the encapsulation of data and operation
# Objects are independent, but they can interact with each other.
# At present, OOP is the programming paradigm closest to human cognition.
Why do you need object-oriented programming?

Process-oriented: high development cost, small problem solving limitations
Object-oriented: low development cost, problem solving is limited to the object

Question:'abc' => {'a','b','c'}
Process-oriented: hand-drawn
Object-oriented: str => list => set

Development: preferred object-oriented (find the object to solve the problem),
Then consider finding multiple objects (a combination of object-oriented and process-oriented),
Finally, I encapsulate an object that can solve the problem by myself (the external is the embodiment of object-oriented, and the core of internal problem-solving is process-oriented)

Related knowledge of the class####

Declaration of classes and objects#####
classClassName:
Statement block
# 1. Must use the class keyword
# 2. The class name must use camel case
# 3. After the class definition is completed, a class object is generated, which is bound to ClassName.classStudent:"""YouMen"""
 age =21 #first part:Static attributes attributes static variables static fields
 def foo(self):print(self.age)return self.age

print(Student)              #Printing
print(Student.__name__)     #Print class name
print(Student.foo)          #Functions in the print object
print(Student.age)          #Static properties in the print class
print(Student.__doc__)      #Print comments in the class
print(type(Student))

# Objectify
mycls =Student()           #Instantiate
print(type(Student))
mycls.foo()print(mycls.foo())<class'__main__.Student'>
Student
< function Student.foo at 0x000001C1E9FE1EA0>21
YouMen
< class'type'><class'type'>212121

# Class objects and class attributes
# Class object, the definition of the class will generate a class object
# Class attributes, 类定义中的变量和类中定义的方法都是Class attributes.
# Class variable,x is an attribute of Student,__doc__Is also an attribute of the class
# The foo method is an attribute of the class, if eating is a human method, but every specific person can eat,
# In other words, methods that can only be called by human instances.
# foo is a method object, not an ordinary function object function, it must have at least one parameter
# And the first parameter must be self(self can change name),This parameter position is left to self.
# Here self refers to the current instance itself.
What is an object?

The object comes out of the class, as long as the class name adds (), it is an instantiation process, this will instantiate an object.
When we write demo1 = ClassName() to instantiate the object, he will automatically execute the init method

What happened to instantiating an object?

# 1. Open up an object space in memory.
# 2. Automatically execute in the class__init__method,And this object space(Memory address)Passed to__init__method的第一个位置参数self.
# 3. in__init__Add attributes to the object space through self in the method
Object Operation Object Space Attribute#####
# __ init__method
# MyClass()Is actually calling__init(self)Method, can not be defined, if not defined, it will be called implicitly after instantiation.
# effect:Initialize the instance.classStudent:"""this is a class"""
 mind ='Thoughtful'
 language ='Language used'
 def __init__(self,name,sex,age,hobby):
  # self and obj point to the same memory address and the same space, the following is to encapsulate four attributes for this object space through self
  self.n = name
  self.s = sex
  self.a = age
  self.h = hobby

obj =Student('youmen','male','18','movement')print(obj.__dict__){'n':'youmen','s':'male','a':'18','h':'movement'}

The single attribute of the object operation object, the universal point

obj =Student('youmen','male','18','movement')
obj.job ='python'      #Add attribute job
del obj.n               #Delete the name attribute of Obj
obj.s ='Female'            #change
print(obj.s)print(obj.__dict__)     #check

# Female
# {' s':'Female','a':'18','h':'movement','job':'python'}

Object view properties in the class

obj =Student('youmen','male','18','movement')print(obj.mind)print(obj.language)
obj.a =88print(obj.a)

# Thoughtful
# Language used
# 88

Methods in the object operation class

classStudent:"""this is a class"""
 mind ='Thoughtful'
 language ='Language used'
 def __init__(self,name,sex,age,hobby):
  # self and obj point to the same memory address and the same space, the following is to encapsulate four attributes for this object space through self
  self.n = name
  self.s = sex
  self.a = age
  self.h = hobby

 def work(self):print(self)print('Humans will work')

 def tools(self):print('Humans use tools')
obj =Student('youmen','male','18','Deep thinking')
obj.work()
obj.tools()

# <__ main__.Student object at 0x0000021E46230588>
# Humans will work
# Humans use tools

The methods in the class are generally executed through objects (except for class methods and static methods), and the object execution of these methods will automatically pass the object space to the first parameter self in the method

What is self?
# self is actually a method in the class(function)The first positional parameter,只不过解释器会自动调用这个function的对象传给self,所以咱们把类中的方法第一个参数约定俗称设置为self,Represents this is the object.

# A class can be instantiated into multiple objects

The spatial problem of classes and the relationship between classes####

Class space issues

Where can I add object properties and static properties

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

 def func(self,sex):
  self.sex = sex

 def func1(self):
  A.bbb ='ccc'

# Add object properties outside the class
obj =A('youmen')
obj.age =18print(obj.__dict__)

# Add static properties outside the class
A.aaa ='zhou'print(A.__dict__)

# Add object properties to the class
obj =A('flying')   # __inif__Method can
obj.func('male')print(obj.__dict__)

# The inside of the class can also be added
A.func1(123)print(A.__dict__)

# {' name':'youmen','age':18}
# {'__ module__':'__main__','__init__':<function A.__init__ at 0x0000019395441EA0>,'func':<function A.func at 0x0000019395441D90>,'func1':<function A.func1 at 0x0000019395441F28>,'__dict__':<attribute '__dict__'of'A' objects>,'__weakref__':<attribute '__weakref__'of'A' objects>,'__doc__': None,'aaa':'zhou'}

# {' name':'flying','sex':'male'}
# {'__ module__':'__main__','__init__':<function A.__init__ at 0x0000019395441EA0>,'func':<function A.func at 0x0000019395441D90>,'func1':<function A.func1 at 0x0000019395441F28>,'__dict__':<attribute '__dict__'of'A' objects>,'__weakref__':<attribute '__weakref__'of'A' objects>,'__doc__': None,'aaa':'zhou','bbb':'ccc'}

How the object finds the attributes of the class

The object can find the class because there is a class object pointer in the object space.

# Object lookup sequence:First find from the object space--->Class space search--->Parent space search
# Class name lookup order of attributes:First find from this space--->Parent space search

The relationship between class and class

# 1. Dependency
# 2. connection relation
# 3. Combination relationship
# 4. Aggregation relationship
# 5. Realization relationship
# 6. Inheritance

Object-oriented inheritance####

What is inheritance?

Inheritance (English: inheritance) is a concept in object-oriented software technology. If a category A "inherits" from another category B, call this A a "subcategory of B", and calling B the "parent category of A" can also be called "B is a super category of A". Inheritance can make the sub-category have various properties and methods of the parent category without the need to write the same code again. While making the sub-category inherit the parent category, you can redefine some properties and rewrite some methods, that is, overwrite the original properties and methods of the parent category to obtain different functions from the parent category. In addition, it is also common practice to add new attributes and methods to subcategories. In general static object-oriented programming languages, inheritance is static, which means that the behavior of the subcategory is determined at compile time and cannot be expanded during execution.
The literal meaning is: the son inherits his father's inheritance and legally inherits the family property, that is, if you are the only child, and you are also very filial, you will inherit all your parents' property, and all their property will be used by you (except the prodigal son)

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

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

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

# Inherited usage:
classAniaml(object):
 def __init__(self,name,sex,age):
   self.name = name
   self.age = age
   self.sex = sex

classPerson(Aniaml):
 pass

classCat(Aniaml):
 pass

classDog(Aniaml):
 pass

Inherited advantages:

1. Increase the coupling of the class (the coupling should not be too much, it should be fine)

2. Reduced duplicate code

3. Make the code more standardized and rationalized

Inheritance category
# Inheritance can be divided into single inheritance and multiple inheritance

# There are two classes in the Python2x version
# One called classic,In Python2.Before 2, the classic class has been used. If the classic class is not written at the root of the base class.
# A new class,In Python2.After 2 a new class appeared, characterized by the root of the base class is the Object class.

# There is only one class in the Python3x version
# Python3 uses new-style classes, if no one inherits the base class, then this class will inherit Object
Single inheritance

Class name, the object executes the parent class method

classAniaml(object):
 type_name ='Animal'

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

 def eat(self):print(self)print('Eat something')classPerson(Aniaml):
 pass

classCat(Aniaml):
 pass

classDog(Aniaml):
 pass

# Class name:
print(Person.type_name)  #You can call the properties and methods of the parent class.
Person.eat(111)print(Person.type_name)

# Object:
# Instantiate object
p1 =Person('Spring brother','male',18)print(p1.__dict__)
# # The properties and methods of the parent class of the object execution class.
print(p1.type_name)
p1.type_name ='666'print(p1)
p1.eat()

# Class name, the object calls the parent class method respectively

Order of execution

classAniaml(object):
 type_name ='Animal'
 def __init__(self,name,sex,age):
   self.name = name
   self.age = age
   self.sex = sex

 def eat(self):print(self)print('Eat something')classPerson(Aniaml):
    
 def eat(self):print('%s eat'%self.name)classCat(Aniaml):
 pass

classDog(Aniaml):
 pass

p1 =Person('barry','male',18)
# Must be executed when instantiating an object__init__method,Not in the class, find from the parent class, and not in the parent class, find from the object class.
p1.eat()
# You must execute the eat method in your own class first, and the method in the parent class can only be executed without your own class.

# Execution order

Simultaneous execution of class and parent class methods

method one

If you want to execute the func method of the parent class, this method is also used in the subclass, then write in the method of the subclass:

Parent class.func(object, other parameters)

classAniaml(object):
 type_name ='Animal'
 def __init__(self,name,sex,age):
   self.name = name
   self.age = age
   self.sex = sex

 def eat(self):print('Eat something')classPerson(Aniaml):
 def __init__(self,name,sex,age,mind):'''
  self = p1
  name ='Spring brother'
  sex ='laddboy'
  age =18
  mind ='Thoughtful''''
  # Aniaml.__init__(self,name,sex,age)  #method one
  self.mind = mind

 def eat(self):super().eat()print('%s eat'%self.name)classCat(Aniaml):
 pass

classDog(Aniaml):
 pass

# Method 1: Aniaml.__init__(self,name,sex,age)
# p1 =Person('Spring brother','laddboy',18,'Thoughtful')
# print(p1.__dict__)

# If you don’t understand method one:
# def func(self):
#  print(self)
# self =3
# func(self)
Multiple inheritance
classShenXian: #immortal
 def fei(self):print("Fairy City⻜")classMonkey: #monkey
 def chitao(self):print("Monkeys like to eat peaches")classSunWukong(ShenXian, Monkey): #Monkey King is a god,At the same time a monkey
 pass
sxz =SunWukong() #Monkey King
sxz.chitao() #Can eat peaches
sxz.fei() #Meeting ⻜

At this time, Monkey King is a monkey, and he is also a god. That Monkey King inherited these two classes. Monkey King can execute the methods in these two classes naturally. Multiple inheritance is simple to use. It is also very good. Understand. But in multiple inheritance, there is such a problem. When two types of methods have the same name. What should I do? Then it involves how to find the type of methods. This is a problem. That is, the MRO (method resolution order) problem. This is a very complicated problem in python. Because different python versions use different algorithms to complete MRO.

` There is no classic class in python3, but the MRO of the classic class can be learned, and there may be a written test.

# Example3
# Multi-parameter
classPerson:
 x ='flying'
 def __init__(self,name,age=19):
  self.name = name
  self.y = age
 """ this is a Person class"""

 def show(self,x,y):print(self.name,self.x,x,y)
  self.y = x
        
a =Person('tom')
b =Person('alice',18)print(a.name,a.y,b.name,b.y)print(a.x,b.x)
a.show(a.y,b.y)print(a.y)
# __ init__()The method cannot have a return value, it will only return Nove
# After the class is instantiated, an object will be obtained, which is the instance object.
# Tom in the above example,alice is an instance of Person.
# __ init__The first parameter self of the method refers to an instance.
# Example4
classStudent:
 def __init__(self):print('self in init = {}'.format(id(self)))

c =Student()   #Will call__init__
print('c = {}'.format(id(c)))

# The output is:
self in init =46710672
c =46710672

# The above example shows that self is the caller,Is the instance object corresponding to c.
# The name self is just a convention, he can modify it,But please do not modify, otherwise it will affect the readability of the code.
# Example6
classPeople:
 name ='people'

p1 =People()
p2 =People()

# Conclusion 1:The namespace of the class and each object is independent
print(p1.__dict__)print(p2.__dict__)print(People.__dict__)

# Conclusion 2:Class and every object can use the name in the class
print(People.name)print(p1.name)print(p2.name)

# Conclusion 3:Object access name, priority access to its own, no more access to the class
p1.name ='Zhang San'
p2.user ='Li Si'print(People.name)print(p1.name)print(p2.user)print(p2.name)

# Focus
# Object operation name, the operation is the object, the class operation name is the class, and they do not interfere with each other
# Class can only access the name of the class
# Object access name, priority access to itself, but no more access to the class

{}{}{'__ module__':'__main__','name':'people','__dict__':'__weakref__'of'People' objects>,'__doc__': None}
people
people
people
people
Zhang San
Li Si
people

Class initialization method

# You can quickly instantiate each object for the class, resulting in multiple names in the object namespace

classNewTeacher:
 def __init__(self,name,sex,age):
  # print(id(self))    #self is the object produced by instantiation(nt1)
  # print('init is called')
  self.name = name
  self.sex = sex
  self.age = age
 pass

# Class() is calling the class__init__method
nt1 =NewTeacher('YouMen','Man',30)print(nt1.name,nt1.sex,nt1.age)

nt2 =NewTeacher('flying','Man',40)print(nt2.name,nt2.sex,nt1.age)

Class method classification

Object method: directly defined method, it is recommended to be called by the object, the method in the class needs to use the object's data to define the object method

  1. Object method object call, the default object is passed in to the first parameter
class class name
	def fn(self,*args,**kwargs):pass

Class method: The method modified by classmethod is recommended to be called by the class. The method when the data of the class needs to be used inside the class should be defined as the class method

  1. The class method is called by the class, and the class is passed to the first parameter by default.
class class name:
 @ classmethod
 def fn(cls,*args,**kwargs): pass
  1. Static methods are recommended to be called by the class, and the caller is not passed in by default
@ staticmethod
def fn(*args,**kwargs): pass

Example1:

classBook:
 name ='book'
 def __init__(self,name,price):
  self.name = name
  self.price = price
 # Book details=>Must know that book
 # @ classmethod class call cls is a class, object call is processed into an object.__class__
 def detail(self):
  # print(cls.name)print('%The price of s is:%s yuan'%(self.name,self.price))

book1 =Book('Journey to the West',29.8)
book2 =Book('Water Margin',98.9)
book1.detail()
book2.detail()
# print(book1.__class__)

# Static method: 方法的内部不需要对象及类的参与,所以定义为Static method,But the method must be called by the caller, it is recommended to use the class.classNumTool:  #Tools=>Module
 def max_two(self,n1,n2):
  max_num = n1 if n1 > n2 else n2
  print('The big number is%s'% max_num)
 @ staticmethod
 def new_max_two(n1,n2):
  max_num = n1 if n1 > n2 else n2
  print('The big number is%s'% max_num)

n1 =NumTool()
n2 =NumTool()
n1.max_two(10,20)
n2.max_two(10,20)

NumTool.new_max_two(10,20)
n1.new_max_two(10,20)

Example2:

# Class method: 方法的内部需要类的参与,所以定义为Class method,第一个参数默认传参
classNewNumTool:
 PI =3.14
 @ classmethod
 def new_max_two(cls,n1,n2):
  max_num = n1 if n1 > n2 else n2
  return max_num
    
 @ classmethod
 def new_max_three(cls, n1, n2, n3):
  # max_num ="Want to reuse new_max_two"
  max_num = cls.new_max_two(n1, n2)
  max_num = cls.new_max_two(max_num, n3)return max_num

 @ classmethod
 def is_PI(cls,num):if num == cls.PI:return True
  return False

reslt = NewNumTool.new_max_three(1,5,3)print('The big number is%s'% reslt)print(NewNumTool.is_PI(3.14))

The big number is 5
True

Three object-oriented features####

Package

What is encapsulation?

# &quot;Pack&quot; means to put a series of attributes into a container
# " seal"Means to hide it, it can be seen inside, but it is hidden from outside.

# Package: 把很多数据Package到⼀个对象中. 把固定功能的代码Package到⼀个代码块,function,Object,Packaged into modules. 这都属于Package的思想.Specific analysis of specific circumstances.such as.You wrote a very big function. 那这个也可以被称为Package.In the mind of the facing object.It is to combine some seemingly insignificant content into a unified storage and use. 这就是Package.

Why use encapsulation?

# Encapsulate complex operations into simple interfaces, and strictly control the calling process of the interface

How to use encapsulation

# But any attribute that starts with a double underscore (cannot end with a double underscore) will be hidden and can be used directly inside the class
# The outside of the class cannot be used directly, that is, the package that is not internal to the outside

# This hidden feature:
# 1. It&#39;s just a grammatical deformation, which will transform the initial attributes into:Own class name attribute name(n=1 # __Foon=1)
# 2. This transformation occurs only once in the class definition stage, and the new__The attributes at the beginning are not deformed.
# 3. Concealment is not internal
# 4. In inheritance, if the parent class does not want the subclass to cover its own method of the same name, the method can be made private.

Example1

classTeacher:
 def __init__(self,name,age):
  # self.__name=name
  # self.__age=age
  self.set_info(name,age)

 def tell_info(self):print('Name:%s,age:%s'%(self.__name,self.__age))
 def set_info(self,name,age):if not isinstance(name,str):
   raise TypeError('Name must be string type')if not isinstance(age,int):
   raise TypeError('Age must be integer')
  self.__name=name
  self.__age=age

t=Teacher('tom',18)
t.tell_info()

t.set_info('flying',19)
t.tell_info()

Example2

classStudent(object):
 def __init__(self,name,score):
  self.name=name
  self.score=score
 def get_grade(self):if self.score >=90:return'A'
  elif self.score>=60:return'B'else:return'C'

Tom =Student('Tom',99)
Alice =Student('Alice',57)print(Tom.name,Tom.get_grade())print(Alice.name,Alice.get_grade())

External packaging method

# What is encapsulation:The following attributes and methods of the class are hidden from the outside and visible inside, and become private variables.
# Why package:Add permissions for the operation of attributes and methods, the specific permissions are handled through custom logic

# Means of encapsulation:Add before the class attribute method, object attribute method, and static method name__
# As long as it passes__The name, this naming convention, is to hide
# Nature: __first name 封装隐藏白能量的Nature是 将first name修饰成_Class name__first name

# The way to solve the package externally
# 1. If you really don’t want the outside world to access it, don’t provide a way to access data.
# 2. If you want the outside world to access, you can provide a method to access the data. The method has logic and you can add operation permissions..
classTest:
 def __init__(self,name):
  # __ The name is only hidden from the outside and visible inside
  self.__name = name

 def get_name(self):return self.__name

 def set_name(self,name):if'sh' not in name:    #Modifications to the data may cause data security issues, restrictions can be added
   self.__name = name

# Focus:Optimization of encapsulated external access syntax
classUser:
 def __init__(self,name):
  self.__name = name

 @ property #Disguise methods as attributes
 def name(self):return self.__name

 @ name.setter #Can disguise the set method for the (method) attribute that has the disguised get method
 def name(self, value):
  self.__name = value
    
 @ name.deleter
 def name(self):
  del self.__name

# to sum up
# 1. The object is gone, the properties of the object are gone, so no properties are needed@first name.deleter
# 2. Providing the get method externally is the foundation. @property,If not, the outside world cannot be read or written
# 3. If there is@property,You can@first name.setter,Have set,Read and write, read-only without set.

@ property #Disguised attribute methods, do not necessarily have__The first name advance corresponds to
def pwd(self):return'123456'

u1 =User('Ower')print(u1.name)
# del u1.name
print(u1.name)

Owen
inherit#####
# 1. What is inheritance?
# Inheritance is a way of creating new classes. The newly created classes are called subclasses or derived classes, and the inherited classes are called parent classes or base classes or super classes.
# The subclass will inherit all the properties and methods of the parent class, and you can use these properties and methods directly
# The subclass can automatically own all the content in the class except private attributes.Talked,You can use Dad’s stuff at will.But friends,I must recognize one thing clearly.Must have dad first,After.The order cannot be disordered,Implementing inheritance in python is very simple.When declaring the class,Add a small bracket after the class name,Inheritance relationship.So under what circumstances can inheritance be used??Purely from the code level.When two classes have the same function or feature.Can take the form of inheritance.Extract a class,In this class, the same parts of two classes are written.Then the two classes can inherit this class separately..The advantage of writing this way is that we can avoid writing a lot of repetitive functions and codes.If you analyze it from semantics.Will be much simpler.If x appears in the context, it is a kind of y.At this moment,y is a generalized concept.x is more specific than y.Then x is the subclass of y.such as.Cat is an animal.Cat inherits animal.Animal mobility.Cats can move.At this moment猫在创建的时候就有了move物的"move"This attribute.Another example,White bone spirit is a monster.Youkai Tian has a relatively bad feature called"Eat",The white bone spirit knows how to come out"Eat".At this time, the white bone spirit inherits the fairy.

# 2. Why use inheritance
# Reduce code redundancy
# Let the subclass get all the functions of the parent class.

Suppose we want to implement the following four animals

# Dog -Dog
# Bat -bat
# Parrot -parrot
# Ostrich -ostrich

If classified according to mammals and birds, we can design such a hierarchy of classes:

If categorized according to "can run" and "can fly", we should design such a class level

If we want to include the above two categories, we have to design more levels

* Mammals:  能跑的Mammals,能飞的Mammals
* birds:  能跑的birds,能飞的birds.
# In this way, the class level is complicated.

If you want to add "pet classes" and "non-pet classes", if you continue to do so, the number of classes will increase exponentially. Obviously, this design will not work. The correct approach is multiple inheritance. First, the main class hierarchy Still designed according to mammals and birds

classAnimal(object):
 pass

# Big category:classMammal(Animal):
 pass

classBird(Animal):
 pass

# Various animals:classDog(Mammal):
 pass

classBat(Mammal):
 pass

classParrot(Bird):
 pass

classOstrich(Bird):
 pass

Now we add the functions of Runnable and Flyable to the animals, we only need to define the Runnable and Flyable classes first

classRunnable(object):
 def run(self):print('Running...')classFlyable(object):
 def fly(self):print('Flying...')

For animals that need Runable functionality, one more Runnable is inherited, such as Dog.

classDog(Mammal, Runnable):
 pass

For animals that need Flyable functions, one more Flyable is inherited, such as Bat:

classBat(Mammal, Flyable):
 pass
# Through multiple inheritance, a subclass can obtain all the functions of multiple parent classes at the same time.
# 3. how to use
**Example1**classParent1:
 pass
classParent2:
 pass
classSon1(Parent1):
 pass
# Python supports multiple inheritance, a class can have multiple parent classes, but java has only one
classSon2(Parent2):
 pass
print(Son1.__bases__)print(Son2.__bases__)(<class'__main__.Parent1'>,)(<class'__main__.Parent2'>,)

# Switch python interpreter 3.x >>>2.x draws a conclusion
"""
In python3, if there is no explicit inheritance of any class, the object class is inherited by default
In python2, if no class is explicitly inherited, the object class will not be inherited

There are two types of classes in python:
  New style:
   Any class that inherits object or its subclasses are all new-style classes
   >>>: All classes in python3 are new-style classes
  Classic
   Does not inherit the object class, and the subclasses of this class are all classic classes
   This means that the concept of the classic class and the new style class is only available in python2
   There are only new-style classes in python3
"""

Case of reducing code redundancy based on inheritance + derivation/derivation

Summarize similar characteristics and skills between objects
Summarize similar attributes and characteristics between classes to get the parent class

Example2

import pickle

classOldboyStudent:
 school ='oldboy'

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

 def choice_course(sel):print('%s is choosing course'%self.name)

 def save(self):withopen(self.name,'wb')as f:
   pickle.dump(self,f)classOldboyTeacher:
 school ='oldboy'

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

 def score(self):print('%s is score'%self.name)

 def save(self):withopen(self.name,'wb')as f:
   pickle.dump(self,f)
stu =OldboyStudent('alice',22,'male')
stu.save()

tea =OldboyTeacher('Tom',32,'male',10)
tea.save()

# Let’s look back and see if there are similar parts in the above code. We just learned how to solve code redundancy between classes.
classOldboyPeople:
 school ='oldboy'

 def save(self):withopen(self.name,'wb')as f:
   pickle.dump(self, f)
# Preliminary extraction of inherited classes, thinking about the order in which objects find properties and methods after inheritance
stu.save()
stu.school

# Just talked about the properties and methods being extracted into the parent class, but there are also duplicate codes in init, which should also be extracted
classOldboyPeople:
 school ='oldboy'
 def __init__(self,name,age,sex):
  self.name = name
  self.age = age
  self.sex = sex

 def save(self):withopen(self.name,'wb')as f:
   pickle.dump(self, f)
# Regardless of the difference in init between the teacher and the student, first inherit the unified init of the parent class, and find that the parent class init can also be used

# Derived concept
# While the subclass can use all the properties and methods of the parent class, it also has some additional properties and methods.
# Little thinking:If the derived properties and methods happen to be the same as those of the parent class, who should be found first when looking for properties and methods?>>>Still in search order

# Looking back, there are additional level parameters in the teacher&#39;s init, and default parameters should not be added to the parent class.
# You can only rewrite the init method yourself, but there are duplicate codes
 def __init__(self,name,age,sex,level):
  OldboyPeople.__init__(self,name,age,sex)
  self.level = level
"""
Reuse the method of the parent class in the new method derived from the subclass
Way 1:Visit by name and surname has nothing to do with inheritance
OldboyPeople.__init__(self,name,age,sex)
The implication is that there is also a way to reuse the method of the parent class that is related to inheritance, so don&#39;t worry about it.

Principle of Inheritance

classFoo:
 def f1(self):print('Foo.f1')
    
 def f2(self):print('Foo.f2')
  self.f1() # obj.f1()classBar(Foo):
 def f1(self):print('Bar.f1')

obj=Bar()
obj.f2()

Foo.f2
Bar.f1

Multiple inheritance

# F(A,B,C)Whether it’s a new-style class or a classic class, it’s all going from left to right one by one to the bottom to draw and switch the python version to demonstrate.
# Remember to add the file header coding:utf-8
# 2、 Multi-inheritance attribute lookup &quot;: object itself-》Object class-》Find one branch from left to right

classD:
 # def test(self):
 # print('D')
 pass

classE:
 def test(self):print('E')classF:
 def test(self):print('F')classA(D):
 # def test(self):
 # print('A')
 pass

classB(E):
 def test(self):print('B')classC(F):
 def test(self):print('C')classG(A,B,C):
 # def test(self):
 # print('G')
 pass

obj=G()
obj.test()

B

**Go back and look at the method of calling the parent class through inheritance **

# Method 2: super(Own class name,self).Method name in the parent class()
# Calling super will get a special object, which is specifically used to refer to methods in the parent class.
# Specifically: The object will look up attributes from the parent class of the current class in strict accordance with the MRO list of the current class, that is, this method is strictly dependent on inheritance
# ps:Can be abbreviated as super in python3()classOldboyPeople:
 def __init__(self,name,age,sex):
  self.name = name
  self.age = age
  self.sex = sex

classOldboyTeacher(OldboyPeople):
 def __init__(self,name,age,sex,level):
  # OLdboyPeople.__init__(self,name,age,sex)super(OldboyTeacher,self).__init__(name,age,sex)
  self.level=level
tea1=OldboyTeacher('alice',18,'male',10)print(tea1.name,tea1.level)classA:
 def f1(self):print('A')super().f2()    # super()Will continue to search based on the current and the search position

 def f2(self):print('A')classB:
 def f2(self):print('B')classC(A,B):
 def f2(self):print('C')
obj=C()print(C.mro())
obj.f1()

alice 10[<class'__main__.C'>,<class'__main__.A'>,<class'__main__.B'>,<class'object'>]
A
B
# Use multiple inheritance with caution in actual work. Programming is decoupling, while inheritance is strong coupling.

Mixin

When designing the inheritance relationship of a class, usually the main line is inherited from a single inheritance. For example, Ostrich inherits from Bird, but if you need to mix in additional functions, you can achieve it through multiple inheritance. For example, let Ostrich inherit from Bird. , And then inherit Runnable at the same time, this design is called Mixin.

In order to better see the inheritance relationship, we changed Runnable and Flyable to RunnableMixIn and FlyableMixIn. Similarly, you can also define the carnivorous animal CarnivorousMixIn and the herbivore animal HerbivoresMixIn, so that an animal has several MixIns at the same time:

classDog(Mammal, RunnableMixIn, CarnivorousMixIn):
 pass

The purpose of MixIn is to add multiple functions to a class. In this way, when designing a class, we give priority to combining the functions of multiple MixIns through multiple inheritance, rather than designing multiple levels of complex inheritance relationships.
Many libraries that come with Python also use MixIn. For example, Python comes with two types of network services: TCPServer and UDPServer. To serve multiple users at the same time, you must use a multi-process or multi-thread model. These two models are composed of ForkingMixIn and ThreadingMixIn provide. Through combination, we can create suitable services.

For example, to write a TCP service in multi-process mode, the definition is as follows:

classMyTCPServer(TCPServer, ForkingMixIn):
 pass

Write a multi-threaded UDP service, defined as follows:

classMyUDPServer(UDPServer, ThreadingMixIn):
 pass

If you plan to develop a more advanced coroutine model, you can write a CoroutineMixIn:

classMyTCPServer(TCPServer, CoroutineMixIn):
 pass

**In this way, we don't need a complicated and huge inheritance chain, as long as we choose to combine the functions of different classes, we can quickly construct the required class. **Summary

Since Python allows multiple inheritance, MixIn is a common design.
Languages that only allow single inheritance (such as Java) cannot use MixIn's design.

Polymorphism#####

What is polymorphism

# Multiple forms of the same thing (animal:People, cats, dogs)
# The same object,Multiple forms.This is actually not easy to explain in python.Because we are always using.Just didn&#39;t say specifically.such as.We create a variable a=10,We know that at this time a is an integer type.But we can program a="alex",At this moment,a⼜ becomes a string type.This is what we all know.but,What i want to tell you is.This is polymorphism.The same variable a can have multiple forms.

Why use polymorphism

# Polymorphism:Refers to the method that can directly call the object without considering the specific type of the object

How to use polymorphism

classAnimal:
 def talk(self):
  pass

classPeople(Animal):
 def talk(self):print('say hello')classDog(Animal):
 def talk(self):print('Barking')classcat(Animal):
 def talk(self):print('Meow meow meow')
peo1=People()
dog1=Dog()
cat1=cat()

# Directly call the method of the object without considering the specific type
peo1.talk()
dog1.talk()
cat1.talk()"""
Then think about whether there are many brands of cars. Do you need to learn how to drive a car of that brand?
"""

# Polymorphism has been used before, and the method of the object is directly called without considering the specific type of the object
l =list([1,2,3])
s =str('hello')
t =tuple((4,5,6))

l.__len__()
s.__len__()
t.__len__() #I don’t need to consider these three specific types, as long as it is a container type, the len method can be called
classAnimal:
 def talk(self):
  pass

classPeople(Animal)
 def jian(self):print('say hello')classDog(Animal):
 def han(self):print('Barking')classCat(Animal):
 def hou(self):print('Meow meow meow')
# The condition for the realization of polymorphic performance is that the parent class defines a standard for the child class, animals must be able to call, and the call method must be talk
# But can you now restrict me to say that the subclass must call this method?

# Is there a situation where it can be said that the subclass must follow the standard defined by the parent class
import abc
classAnimal(metaclass=abc.ABCMeta): #The meaning of the existence of the parent class is to define the specification
 @ abc.abstractmethod
 def talk(self):
  pass
# Aoimal()Abstract base class cannot be instantiated()classPeople(Animal):
 def jian(self):print('say hello')classDog(Animal):
 def han(self):print('Barking')classCat(Animal);
 def hou(self):print('Meow meow meow')
# Show off three classes on it, you will get an error when instantiated
# But Python promotes freedom, simplicity does not want to limit programmer development
classPeople:
 def talk(self):print('say hello')classDog:
 def talk(self):print('Barking')classCat:
 def talk(self):print('Meow meow meow')
# Looking at Linux again, everything is a file!
classDisk:
 def read(self):print('disk read')
 def write(self):print('disk write')classProcess:
 def read(self):print('processes')
 def write(self):print('processes write')classMemory:
 def read(self):print('memory read')
 def write(self):print('memory write')
Get object information

First, let's determine the object type, using the type() function:

# Basic types can be used`type()`judgment:

>>> type(123)<class'int'>>>>type('str')<class'str'>>>>type(None)<type(None)'NoneType'>

# If a variable points to a function or class, you can also use`type()`judgment:
>>> type(abs)<class'builtin_function_or_method'>>>>type(a)<class'__main__.Animal'>>>>type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False

Use isinstance()

For the inheritance relationship of class, it is very inconvenient to use type(). To determine the type of class, we can use the isinstance() function.
We assume that the inheritance relationship is:

# Object --> Animal  --> Dog  --> Husky
# Then,isinstance()Can tell us whether an object has a certain type,First create three types of objects:
# isinstance()What is judged is whether an object is the type itself, or is located in the parent inheritance chain of the type.
# type()The basic type of judgment can also use isinstance()judgment.

dir()

# If you want to get all the attributes and methods of an object, you can use dir()Function, he returns a list containing strings,such as,
# Get all the attributes and methods of a str object.
str ='ABC'print(type(str))print(dir(str))

len

# similar`__xxx__`The attributes and methods of are used for special purposes in Python, such as`__len__`The method returns the length.
# In Python, if you call`len()`The function tries to get the length of an object, in fact, in`len()`Inside the function,
# It automatically calls the object`__len__()`Method, so the following code is equivalent:
>>> len('ABC')3>>>'ABC'.__len__()3
# The class we wrote ourselves, if we also want to use len(myObj)Then write one yourself__len__()method.classMyDog(object):
 def __len__(self):return100

dog =MyDog()print(len(dog))

lower()

# There are some common attributes or methods,Such as lower()Return lowercase string.>>>'ABC'.lower()'abc'

getattr,setattr,hasattr

# Just listing properties and methods is not enough,With getattr(),setattr()And hasattr(),We can manipulate the state of an object.classMyObject(object):
 def __init__(self):
  self.x =9
 def power(self):return self.x * self.x

obj =MyObject()print(obj.power())
# Then we can test the properties of the object
print(hasattr(obj,'x'))print(obj.x)setattr(obj,'y',19)print(hasattr(obj,'y'))print(obj.y)
# If you get a non-existent attribute, an AttributeError will be thrown.
# You can pass in a default parameter, if the attribute does not exist, return the default value
print(getattr(obj,'z',404))

# Methods of obtaining objects
print(hasattr(obj,'power')) #Has attributes'power'Is it
print(getattr(obj,'power')) #Get attributes'power'
fn =getattr(obj,'power')   #Get attributes'power'And assign to variable fn
print(fn())print(fn)

summary

Through a series of built-in functions, we can analyze any Python object and get its internal data. It should be noted that we will only get the object information when we don’t know the object information. If we can write it directly :

sum = obj.x + obj.y
# Don&#39;t write
sum =getattr(obj,'x')+getattr(obj,'y')
# A correct example is as follows
def readImage(fp):ifhasattr(fp,'read'):returnreadData(fp)return  None
# Suppose we want to read an image from the file stream fp, we must first determine whether the fp object has a read method, if it exists, the object is a stream.
# If it does not exist, it cannot be read. hasattr()It came in handy.

# Please note that in dynamic languages like Python, depending on the duck type, there is read()Method, does not mean that the fp object is a file stream,
# It may also be a network stream,It may also be a byte stream in memory,But just read()The method returns valid image data,Does not affect the function of reading images
Instance attributes and class attributes

Since Python is a dynamic language, the instance created by the class can be bound to any attributes.
The method of binding properties to an instance is through instance variables, or through self variables.

classStudent(object):
 def __init__(self,name):
  self.name = name

s =Student('Alice')
s.score =90>but if`Student`Does the class itself need to bind a property? You can define attributes directly in the class,
# This attribute is a class attribute,`Student`Class ownership:
classStudent(object):
 name ='Student'>When we define a class attribute, although this attribute is classified, all instances of the class can be accessed. Let&#39;s test it:

classStudent(object):
 name ='Student'

s =Student()print(s.name)print(Student.name)

s.name ='YouMen'print(s.name)   #Since the instance attribute has priority over the class attribute, it will block the name attribute of the class

del s.name  #If you delete the name attribute of the instance
print(s.name)   #Call s again.name,Since the Name attribute of the instance is not found, the attributes of the class are displayed

As can be seen from the above example, when writing a program, do not use the same name for the instance attribute and the class attribute, because the instance attribute with the same name will shield the class attribute, but when you delete the instance attribute, use With the same name, the access will be the class attribute.

summary

# Instance attributes belong to each instance and do not interfere with each other
# Class attributes belong to the class, all instances share an attribute
# Do not use the same name for instance attributes and class attributes, otherwise it will cause hard-to-find errors.

Decorator in class####

property

# The body&#39;s BMI index
"""
Adult BMI value:
Too light: less than 18.5
Normal: 18.5-23.9
Overweight: 24-27
Obesity: 28-32
Very obese,Higher than 32
Body Mass Index (BMI)=Weight (kg)/height^2(m)
  EX:70kg÷(1.75×1.75)=22.86"""

classPeople:
 def __init__(self,name,height,weight):
  self.name=name
  self.height=height
  self.weight=weight
 @ property
 def bmi(self):return self.weight /(self.height **2)

youmen=People('YouMen',1.78,55)
youmen.height=1.78print(youmen.bmi)

To understanding

classPeople:
 def __init__(self,name):
  self.__name=name

 @ property
 def name(self):return self.__name

 @ name.setter
 def name(self,va1):
  # print('====>Ready to modify the value of the name:',val)iftype(va1) is not str:
   raise TypeError('The value of the name must be of type str')
  self.__name=val
    
 @ name.deleter
 def name(self):
  # def self.__name
  print('Don&#39;t let me delete it, brother stay')
# classmethod
# staticmethod

reflection####

What is reflection?

The concept of reflection was first proposed by Smith in 1982. It mainly refers to the ability (introspection) of a program to access, detect, and modify its own state or behavior. The proposal of this concept quickly led to research on applied reflectivity in the field of computer science. It was first adopted by the design field of programming language, and achieved achievements in Lisp and object-oriented.

**Python object-oriented reflection: manipulate object-related attributes in the form of strings, everything in Python is an object (reflection can be used) **Get attributes or methods of a class or object through strings

Reflection: refers to manipulating the properties of a class or object through strings

classPeople:
 country='China'
 def __init__(self,name):
  self.name=name
obj=People('YouMen')

# Four built-in functions are involved
# hasattr
print('country'in People.__dict__)print(hasattr(People,'country'))

# getattr
print(People.__dict__['country'])print(getattr(People,'country'))print(getattr(People,'country1111',None))

# delattr
delattr(People,'country')print(People.__dict__)

application

classftp:
 def get(self):print('get...')

 def put(self):print('put...')

 def auth(self):print('auth...')
    
 def run(self):while True:
   cmd=input('>>>:').strip() # cmd='get'ifhasattr(self,cmd):
    method =getattr(self,cmd)method()else:print('The output method does not exist')
obj=ftp()
obj.run()

Object-oriented advanced programming####

Use slots

Under normal circumstances, when we define a class and create an instance of the class, we can bind any properties and methods to the instance. This is the flexibility of dynamic languages.

classStudent(object):
 pass

# Then, try to bind a property to the instance
s =Student()
s.name ='Michael'  #Dynamically bind a property to the instance
print(s.name)

# You can also try to bind a method to the instance:from types import MethodType

def set_age(self,age):
 self.age = age

s.set_age =MethodType(set_age,s)   #Bind a method to the instance
s.set_age(25)print(s.age)

# But the method bound to one instance does not work for another instance.>>> s2 =Student() #Create a new instance
>>> s2.set_age(25) #Try to call method
Traceback(most recent call last):
 File "<stdin>", line 1,in<module>
AttributeError:'Student' object has no attribute 'set_age'

# In order to bind methods to all instances, you can bind methods to class.from types import MethodType
def set_score(self,score):
 self.score=score
 return score

Student.set_score = set_score
# After binding the method to the class, all instances can be called:print(s.set_score(34))

**Under normal circumstances, the above set_score method can be directly defined in the class, but dynamic binding allows us to dynamically add functions to the class during the running of the program, which is difficult to achieve in a static language **Use sllots

But what if we want to limit the attributes of the instance? For example, only allow the name and age attributes to be added to the Student instance.
In order to achieve the purpose of restriction, Python allows defining a special slots variable when defining a class to limit the attributes that can be added to the class instance.

classStudent(object):
 __ slots__ =('name','age')

# Then we try
s =Student()   #Create a new instance
s.name ='Michael'  #Binding properties'name'
s.age =25      #Binding attribute age
# s.score =99    #Bound attribute score

Since'score' is not placed in __slots__, the score attribute cannot be bound. Trying to bind score will get an error of AttributeError.
When using __slots__, it should be noted that the attributes defined by __slots__ only affect the current class instance, and have no effect on inherited subclasses:

>>> classGraduateStudent(Student):...     pass
...>>> g =GraduateStudent()>>> g.score =9999

Unless __slots__ is also defined in the subclass, in this way, the attributes allowed for the subclass instance are its own __slots__ plus the parent class's __slots__.

Use @property

When binding properties, if we expose the properties directly, although it is simple to write, there is no way to check the parameters, so we can change the results at will.

s =Student()
s.score =9999

This is obviously not logical, in order to limit the scope of score, you can set the score through a set_score() method, and get the score through a get_score(), so that in the set_score() method, you can check the parameters.

classStudent(object):

 def get_score(self):return self.__score

 def set_score(self,value):if not isinstance(value,int):
   raise ValueError('score must be an integer')if value <0 or value >100:
   raise ValueError('score must between 0 ~ 100')
  self.__score = value
# Now, if you operate on any Student instance, you cannot set the score as you want.
s =Student()
s.set_score(60)print(s.get_score())
# s.set_score(1000)
# print(s.get_score())
Custom class#####

When you see variables or function names like slots, which are in the form of __xxx__, you must pay attention to them. These have special uses in Python.
__ We already know how to use slots__, and we also know that the __len__() method is to allow the class to act on the len() function.
In addition, there are many such special-purpose functions in the Python class, which can help us customize the class.

str****We first define a Student class and print an instance:

classStudent(object):
 def __init__(self,name):
  self.name = name

print(Student('YouMen'))<__main__.Student object at 0x018EAEF0>

# We feel that printing this address value is not very beautiful,How to print good looking Nepalese,Just need to be defined__str__()Method, just return a nice string.classStudent(object):
 def __init__(self,name):
  self.name = name
 def __str__(self):return'Student object (name: %s)'% self.name
print(Student('YouMen'))
Student object(name: YouMen)
# The printed example is not only good-looking, but also easy to see the important data inside the example.
# But you will find that the printing example is still not good without printing.
# This is because the direct display variable is not called__str__(),But__repr__()Return the string that the user sees,
# and__repr__()Returns the string seen by the program developer, that is to say,__repr__()Is for debugging

# The solution is to define another__repr__(),But usually__str__()with__repr__()The code is the same, so there is a lazy way of writing.
classStudent(object):
 def __init__(self, name):
  self.name = name
 def __str__(self):return'Student object (name=%s)'% self.name
 __ repr__ = __str__

iter

If a class wants to be used in a for ... in loop, similar to a list or tuple, it must implement a __iter__() method, which returns an iteration object, and then the Python for loop will continue to call The __next__() method of this iteration object gets the next value of the loop until it exits the loop when it encounters a StopIteration error.

Let's take the Fibonacci sequence as an example and write a Fib class that can be used in a for loop:

classFib(object):
 def __init__(self):
  self.a,self.b =0,1 #Initialize two objects

 def __iter__(self):return self         #The instance itself is an iterative object, so return to itself

 def __next__(self):
  self.a,self.b = self.b,self.a + self.b #Calculate the next value
  if self.a >10000: #Conditions for exiting the loop
   raise StopAsyncIteration()return self.a       #Return the next value.for i inFib():print(i)

getitem

Although the Fib instance can be used in a for loop, it looks a bit like a list, but it is still not good to use it as a list. For example, take the fifth element:

classFib(object):
 def __getitem__(self, i):
  a,b=1,1for x inrange(i):
   a,b = b,a+b
  return x

a=Fib()print(a.__getitem__(324))
# Now, you can access any item of the series by pressing the tab.

# But if you want to slice like a list,But this Fib reported an error
classFib(object):
 def __getitem__(self, n):ifisinstance(n, int): #n is the index
   a, b =1,1for x inrange(n):
    a, b = b, a + b
   return a
  ifisinstance(n, slice): #n is the slice
   start = n.start
   stop = n.stop
   if start is None:
    start =0
   a, b =1,1
   L =[]for x inrange(stop):if x >= start:
     L.append(a)
    a, b = b, a + b
   return L
f =Fib()print(f[0:5])

getattr

Under normal circumstances, when we call a method or property of a class, if it does not exist, an error will be reported. For example, define the Student class:

classStudent(object):
    
 def __init__(self):
  self.name ='Michael'

# transfer`name`属性,没问题,但是,transfer不存在的`score`Properties, there is a problem:
# The error message tells us clearly that it was not found`score`This attribute.
# To avoid this error, in addition to adding a`score`In addition to attributes, Python has another mechanism,
# That is to write one`__getattr__()`Method, which dynamically returns an attribute. amend as below
classStudent(object):
 def __init__(self):
  self.name ='YouMen'

 def __getattr__(self, attr):if attr =='score':return404

s =Student()print(s.name)print(s.score)

# Return function is also completely possible.classStudent(object):
 def __init__(self):
  self.name ='YouMen'

 def __getattr__(self, sttr):if sttr =='age':return lambda:25

s =Student()print(s.name)print(s.score)

# Note that it is only called if the attribute is not found`__getattr__`,Existing attributes, such as`name`,Won&#39;t be`__getattr__`Find in
# In addition, note that arbitrary calls such as`s.abc`Will return`None`, This is because we defined`__getattr__`The default return is`None`。
# To make the class respond to only a few specific attributes, we must follow the convention and throw`AttributeError`mistake:
classStudent(object):
 def __init__(self):
  self.name ='YouMen'

 def __getattr__(self, sttr):if sttr =='age':return lambda:25
  raise AttributeError('\'Student\' object bas no attribute \'%s\''% sttr)

a =Student()print(a.sttr)

In fact, all the attributes and method calls of a class can be processed dynamically without any special means.
What is the practical effect of this completely dynamic call feature? The effect is that it can be called for a completely dynamic situation.

for example:
Many websites now use REST APIs, such as Sina Weibo and Douban. The URL for calling the API is similar:
If you want to write an SDK and write a method to the API corresponding to each URL, it will be exhausting, and once the API is changed, the SDK must be changed.
Using the fully dynamic __getattr__, we can write a chain call:

classChain(object):
 def __init__(self,path=''):
  self.__path = path

 def __getattr__(self,path):returnChain('%s/%s'%(self.__path,path ))

 def __str__(self):return self.__path
 __ repr__ = __str__

a =Chain()print(a.status.user.timeline.list)/status/user/timeline/list

# In this way, no matter how the API changes, the SDK can implement a completely dynamic call based on the URL, and it will not change with the increase of the API!
# There are also some REST APIs that put parameters in the URL, such as the GitHub API:
` GET /users/:user/repos`
# When calling, you need to put`:user`Replace with the actual user name. If we can write a chain call like this:
` Chain().users('michael').repos`
# You can call the API very conveniently. Children&#39;s shoes who are interested can try to write it out.

call

An object instance can have its own attributes and methods. When we call an instance method, we call it with instance.method(). Can it be called directly on the instance itself? In Python, the answer is yes.
For any class, you only need to define a __call__() method, and you can directly call the instance. Look at the example:

classStudent(object):
 def __init__(self,name):
  self.name = name

 def __call__(self):print('My name is %s.'% self.name)

s =Student('YouMen')s()		#Do not pass in the self parameter

__ call__() can also define parameters. Calling an instance directly is like calling a function, so you can think of an object as a function and a function as an object, because there is no fundamental difference between the two.

If you think of an object as a function, then the function itself can actually be created dynamically at runtime, because the instances of the class are created at runtime. In this way, we blur the boundaries between objects and functions.

So, how to judge whether a variable is an object or a function? In fact, more often, we need to judge whether an object can be called. The object that can be called is a Callable object, such as functions and the class instance with __call__() defined above:

>>> callable(Student())
True
>>> callable(max)
True
>>> callable([1,2,3])
False
>>> callable(None)
False
>>> callable('str')
False

Through the callable() function, we can determine whether an object is a "callable" object.

Use enumeration class#####

When we need to define constants, one way is to use uppercase variables to define integers, such as months:

JAN =1  
FEB =2  
MAR =3  
  
NOV =11  
DEC =12

The advantage is simplicity, the disadvantage is that the type is int, and it is still a variable.
A better way is to define a class type for such enumerated types, and then, each constant is a unique instance of class. Python provides the Enum class to achieve this function:

fromenumimport Enum  
Month =Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug'))  
  
# So we get`Month`Type of enumeration class, you can use it directly`Month.Jan`To quote a constant,
# Or enumerate all its members:
  
for name, member in Month.__members__.items():print(name,'=>', member,',', member.value)  
  
# The value attribute is an int constant automatically assigned to the member,The count starts from 1 by default.
# If you need to control the enumeration type more precisely, you can derive a custom class from Enum.
fromenumimport Enum,unique  
  
@ unique  
classWeekday(Enum):  
 Sum =0 #The value of Sum is set to 0
 Mon =1  
 Tue =2  
 Wed =3  
 Thu =4  
 Fri =5  
 Sat =6  
# @ The unique decorator can help us check to ensure that there are no duplicate values
# There are several ways to access these enumerated types:  
day1 = Weekday.Mon  
print(day1)print(Weekday.Sat)print(Weekday(1))for name, member in Weekday.__members__.items():print(name,'=>', member)  
# Courseware, you can use the member name to refer to the enumeration constant, and you can directly obtain the enumeration constant according to the value of the value.

Example1

fromenumimport Enum,unique  
classGender(Enum):  
 Male =0  
 Female =1classStudent(object):  
 def __init__(self,name,gender):  
 self.name = name  
 self.gender = gender  
bart =Student('Bart',Gender.Male)if bart.gender == Gender.Male:print("Test passed")else:print('Test failed')

summary

Enum can define a set of related constants in a class, and the class is immutable, and the members can be directly compared.

Use metaclass

type

The biggest difference between a dynamic language and a static language is that the definition of functions and classes are not defined at compile time, but dynamically created at runtime.

For example, if we want to define a Hello class, we write a hello.py module.

classHello(object):
 def hello(self, name='world'):print('Hello, %s.'% name)

When the Python interpreter loads the hello module, it will execute all the statements of the module in turn. The result of the execution is to dynamically create a class object of Hello. The test is as follows:

cat hello.py 
#! /usr/bin/python3
classHello(object):
	def hello(self,name='world'):print('Hello,%s'% name)

cat type_demo.py 
#! /usr/bin/python3
from hello import Hello
h =Hello()
h.hello()print(type(h))

python3 type_demo.py 
Hello,world
< class'hello.Hello'>
# tyep()The function can view a type or the type of a variable,`Hello`Is a class, its type is`type`,
# and`h`Is an instance, its type is class`Hello`。

# We say that the definition of class is dynamically created at runtime, and the way to create a class is to use`type()`function.

# ` type()`Functions can return the type of an object, and can create new types, for example,
# We can pass`type()`Function created`Hello`Class without passing`class Hello(object)...`Definition:

To create a class object, the type() function passes in three parameters in turn:

1. the name of the class;
2. Collection of inherited parent classes. Note that Python supports multiple inheritance. If there is only one parent class, don’t forget the single element writing of tuple;
3. The method name of the class is bound to the function, here we put the function`fn`Bind to method name`hello`on.

The class created by the type() function is exactly the same as writing class directly, because when the Python interpreter encounters a class definition,
Just scan the syntax of the class definition, and then call the type() function to create the class.

Under normal circumstances, we use class Xxx... to define classes, but the type() function also allows us to dynamically create classes. That is to say, the dynamic language itself supports dynamic creation of classes at runtime. It is very different from a static language. To create a class during the runtime of a static language, you must construct a source code string and then call the compiler, or use some tools to generate bytecode. In essence, it is dynamic compilation, which is very complicated.

metaclass

In addition to dynamically creating classes using type(), to control the creation behavior of classes, you can also use metaclass.

metaclass, literally translated as metaclass, the simple explanation is:

After we define the class, we can create an instance based on this class, so: first define the class, and then create the instance.
But what if we want to create a class? Then you must create a class based on the metaclass, so: first define the metaclass, and then create the class.
The connection is: define the metaclass first, then create the class, and finally create the instance.
Therefore, metaclass allows you to create or modify classes. In other words, you can think of a class as an "instance" created by a metaclass.
Metaclass is the most difficult to understand and also the most difficult to use magic code in Python object-oriented. Under normal circumstances, you will not encounter the need to use metaclass, so it does not matter if the following content is not understood, because basically you will not use it.
Let's look at a simple example first. This metaclass can add an add method to our custom MyList:

Define ListMetaclass. According to the default habit, the class name of metaclass always ends with Metaclass, in order to clearly indicate that this is a metaclass:

# metaclass is the template of the class, so it must be from`type`Type derivation:
classListMetaclass(type):
 def __new__(cls, name, bases, attrs):
  attrs['add']= lambda self, value: self.append(value)return type.__new__(cls, name, bases, attrs)

With ListMetaclass, when we define the class, we also instruct to use ListMetaclass to customize the class, passing in the keyword parameter metaclass:

classMyList(list, metaclass=ListMetaclass):
 pass

When we pass in the keyword parameter metaclass, the magic comes into effect. It instructs the Python interpreter to create MyList through ListMetaclass.__new__(), where we can modify the definition of the class , For example, add a new method, and then return to the revised definition.
__ The parameters received by the new__() method are:

  1. Objects of the class currently to be created;
  2. The name of the class;
  3. The collection of parent classes inherited by the class;
  4. The collection of methods of the class.

Test whether MyList can call the add() method:

>>> L =MyList()>>> L.add(1)>> L
[1]

The ordinary list does not have the add() method:

>>> L2 =list()>>> L2.add(1)Traceback(most recent call last):
 File "<stdin>", line 1,in<module>
AttributeError:'list' object has no attribute 'add'

What is the significance of dynamic modification? Wouldn't it be easier to write the add() method directly in the definition of MyList? Under normal circumstances, it should be written directly, and modification through metaclass is purely abnormal.
However, you will always encounter the need to modify the class definition through metaclass. ORM is a typical example.

The full name of ORM is "Object Relational Mapping", that is, object-relational mapping, which maps a row of a relational database to an object, that is, a class corresponds to a table. In this way, it is easier to write code without directly operating SQL statements.
To write an ORM framework, all classes can only be dynamically defined, because only the user can define the corresponding class according to the structure of the table.

Let's try to write an ORM framework.
The first step in writing a low-level module is to write the calling interface first. For example, if a user uses this ORM framework and wants to define a User class to manipulate the corresponding database table User, we expect him to write this code:

classUser(Model):
 # Define the mapping of class attributes to columns:
 id =IntegerField('id')
 name =StringField('username')
 email =StringField('email')
 password =StringField('password')

# Create an instance:
u =User(id=12345, name='Michael', email='[email protected]', password='my-pwd')
# Save to database:
u.save()

Among them, the parent class Model and the attribute types StringField and IntegerField are provided by the ORM framework, and the remaining magic methods such as save() are all automatically completed by the metaclass. Although the preparation of metaclass will be more complicated, the user of ORM is very simple to use.
Now, we will implement the ORM according to the above interface
First, define the Field class, which is responsible for saving the field names and field types of the database table.

classField(object):

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

 def __str__(self):return'<%s:%s>'%(self.__class__.__name__, self.name)

On the basis of Field, further define various types of Field, such as StringField, IntegerField, etc.

classStringField(Field):

 def __init__(self, name):super(StringField, self).__init__(name,'varchar(100)')classIntegerField(Field):

 def __init__(self, name):super(IntegerField, self).__init__(name,'bigint')

The next step is to write the most complex ModelMetaclass.

classModelMetaclass(type):

 def __new__(cls, name, bases, attrs):if name=='Model':return type.__new__(cls, name, bases, attrs)print('Found model: %s'% name)
  mappings =dict()for k, v in attrs.items():ifisinstance(v, Field):print('Found mapping: %s ==> %s'%(k, v))
    mappings[k]= v
  for k in mappings.keys():
   attrs.pop(k)
  attrs['__mappings__']= mappings #Save the mapping relationship between attributes and columns
  attrs['__table__']= name #Assuming the table name and class name are the same
  return type.__new__(cls, name, bases, attrs)

And the base class Model

classModel(dict, metaclass=ModelMetaclass):

 def __init__(self,**kw):super(Model, self).__init__(**kw)

 def __getattr__(self, key):try:return self[key]
  except KeyError:
   raise AttributeError(r"'Model' object has no attribute '%s'"% key)

 def __setattr__(self, key, value):
  self[key]= value

 def save(self):
  fields =[]
  params =[]
  args =[]for k, v in self.__mappings__.items():
   fields.append(v.name)
   params.append('?')
   args.append(getattr(self, k, None))
  sql ='insert into %s (%s) values (%s)'%(self.__table__,','.join(fields),','.join(params))print('SQL: %s'% sql)print('ARGS: %s'%str(args))

When the user defines a class User(Model), the Python interpreter first looks for metaclass in the definition of the current class User, if not found, it continues to search for metaclass in the parent class Model and finds Then, use the ModelMetaclass of metaclass defined in Model to create the User class. That is to say, the metaclass can implicitly inherit the subclass, but the subclass itself cannot feel it.

In ModelMetaclass, several things are done:

  1. Exclude modifications to the Model class;
  2. Find all attributes of the defined class in the current class (such as User). If a Field attribute is found, save it to a dict of __mappings__, and delete the Field attribute from the class attribute. Otherwise, it is easy Causes runtime errors (the attributes of the instance will cover the attributes of the same name of the class);
  3. Save the table name in __table__, which is simplified to the table name and defaults to the class name.

In the Model class, you can define various methods of operating the database, such as save(), delete(), find(), update, etc.
We have implemented the save() method to save an instance in the database. Because of the table name, attribute-to-field mapping, and attribute value collection, an INSERT statement can be constructed.

Try writing code:

u =User(id=12345, name='Michael', email='[email protected]', password='my-pwd')
u.save()

The output is as follows:

Found model: User
Found mapping: email ==><StringField:email>
Found mapping: password ==><StringField:password>
Found mapping: id ==><IntegerField:uid>
Found mapping: name ==><StringField:username>
SQL: insert into User(password,email,username,id)values(?,?,?,?)
ARGS:['my-pwd','[email protected]','Michael',12345]

As you can see, the save() method has printed out the executable SQL statement and the parameter list. You only need to connect to the database and execute the SQL statement to complete the real function.
In less than 100 lines of code, we implemented a streamlined ORM framework through metaclass

summary

Metaclass is a very magical object in Python, it can change the behavior of the class when it is created. Use this powerful feature with care.

Recommended Posts

10. Object Oriented Python
Learn Python in One Minute | Object Oriented (Part 1)
Python iterable object de-duplication example
Everything in Python is an object
Python multithreading
Python CookBook
Python FAQ
Python3 dictionary
Python3 module
python (you-get)
Python string
Python descriptor
Python basics 2
Python notes
Python3 tuple
CentOS + Python3.6+
Python advanced (1)
Python decorator
Python IO
Python multithreading
Python toolchain
Python3 list
Python multitasking-coroutine
Python overview
python introduction
Python analytic
Python basics
07. Python3 functions
The specific method of python instantiation object
Python basics 3
Python multitasking-threads
Python functions
python sys.stdout
python operator
Python entry-3
Centos 7.5 python3.6
Python string
Python basics 4
Python basics 5