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.
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
# 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.
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.
Process-oriented: high development cost, small problem solving limitations
Object-oriented: low development cost, problem solving is limited to the objectQuestion:'abc' => {'a','b','c'}
Process-oriented: hand-drawn
Object-oriented: str => list => setDevelopment: 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)
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.
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
# __ 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
# 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
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
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 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
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)
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
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
class class name:
@ classmethod
def fn(cls,*args,**kwargs): pass
@ 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
What is encapsulation?
# "Pack" 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'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
# 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'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'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 ": 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
andFlyable
toRunnableMixIn
andFlyableMixIn
. Similarly, you can also define the carnivorous animalCarnivorousMixIn
and the herbivore animalHerbivoresMixIn
, 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
andUDPServer
. To serve multiple users at the same time, you must use a multi-process or multi-thread model. These two models are composed ofForkingMixIn
andThreadingMixIn
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.
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'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')
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'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
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'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.
property
# The body'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't let me delete it, brother stay')
# classmethod
# staticmethod
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()
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__
, thescore
attribute cannot be bound. Trying to bindscore
will get an error ofAttributeError
.
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__
.
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())
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 thelen()
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 aStopIteration
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'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'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.
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.
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 ofHello
. 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 thetype()
function to create the class.Under normal circumstances, we use
class Xxx...
to define classes, but thetype()
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 anadd
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 createMyList
throughListMetaclass.__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:
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 ofMyList
? 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 aUser
class to manipulate the corresponding database tableUser
, 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 typesStringField
andIntegerField
are provided by the ORM framework, and the remaining magic methods such assave()
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 formetaclass
in the definition of the current classUser
, if not found, it continues to search formetaclass
in the parent classModel
and finds Then, use theModelMetaclass
ofmetaclass
defined inModel
to create theUser
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:
Model
class;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);__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 assave()
,delete()
,find()
,update
, etc.
We have implemented thesave()
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