Day08:继承与派生,多态,封装,绑定与非绑定方法,面向对象高级(反射,__str__,__del__)
上节课复习:
1.编程思想
面向过程
核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么后干什么
基于该思想编写程序就好比在设计一条流水线,是一种机械式的思维方式
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差
面向对象
核心是对象二字,对象是特征(变量)与技能(函数)的结合体
基于该思想编写程序就好比在创造一个世界,世界是由一个个对象组成的,在上帝眼里所有存在的事物都是对象,任何不存在的事物也可以创造出来。
优点:可扩展性强
缺点:编程复杂度要高于面向过程
2.类
对象是特征与技能的结合体,而类则是一系列对象相同特征与技能的结合体
对象是具体存在的,而类是总结出来的抽象概念
类本质就是一个容器(名称空间)
对象本质也是一个容器(名称空间)
3.类与对象顺序
在现实世界中:一定是先有一个个具体存在的对象,然后随着人类文明的发展由人站在不同的角度总结出来的种类
在程序中:先定义类,后调用类产生对象
4.定义类
class OldboyStudent:
'''文档注释'''
#相同的特征
school='oldboy'
#相同的技能
def choose_course(self)
pass
注意: 类体代码会在类定义阶段立即执行,产生一个类的名称空间,用来将类体代码执行过程中产生的名字丢进去
5.使用类
两种用途:
1.当作一个容器使用
class OldboyStudent:
school='oldboy'
def choose_course(self):
pass
print(OldboyStudent.school)
OldboyStudent.country='China'
OldboyStudent.school='Oldboy'
del OldboyStudent.school
2.调用类来产生对象
class OldboyStudent:
school='oldboy'
#相同特征
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
#相同技能
def choose_course(self):
pass
stu1=OldboyStudent('andy',18,'male')
调用类会发生两件事
1.产生一个空对象
2.触发类的函数/对象的绑定方法__init__(stu1,'andy',18,'male')
强调__init__:
1.该方法是在产生对象后才调用
2.该方法可以由任意python代码,但唯独就是不能由返回值
6.属性查找
强调:类的属性与对象大的属性,访问时必须加前缀
先从对象自己的名称空间中找,如果没有则去类的名称空间中查找
7.绑定方法
类中定义的函数是类的函数属性,就是一个普通函数,没有自动传参的效果
但类中定义的函数其实是绑定给对象用的,称之为绑定方法,绑定方法的特殊之处
绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个位置参数自动传入
今日内容:
1.继承与派生
2.多态
3.封装
4.绑定方法与非绑定方法
classmethod
staticmethod
5.面向对象高级
反射
__str__
__del__
6.元类(视频)
一.继承
1.什么是继承
继承是一种新建类的方式,新建的类称之为子类,被继承的类称之为基类、父类、超类。
继承描述的是一种“遗传”的关系:子类可以重用父类的属性
python中的继承注意点:
1.在python中支持一个子类同时继承多个父类,
2.python类分类两种:
新式类:但凡继承object的类,以及该类的子/子子..类都是新式类
在python3中一个类如果没有继承类,默认继承object类,即python3中所有类都是新式类
经典类:没有继承object的类,以及该类的子/子子..类都是经典类
python2中才区分新式类和经典类
2.为何要用继承
减少冗余代码
3.如何用继承
class Parent(object):
pass
class Parent2:
pass
class Subclass1(Parent1,Parent2)
pass
print(Subclass1.__bases__)
问题:
1.如何利用继承减少代码冗余
继承解决的式类与类之间的代码冗余问题,一定是一个类是另外一个类的子类
总结对象之间的相似之处就得到类,总结类与类之间的相似之处就是父类
2.在继承的背景下,属性查找优先级
3.新式类与经典类的区别
1 class OldboyStudent: 2 school='Oldboy' 3 def __init__(self,name,age,sex): 4 self.name=name 5 self.age=age 6 self.sex=sex 7 self.score=0 8 def choose_course(self): 9 print('%s is choosing course' %self.name) 10 class OldboyTeacher: 11 school='Oldboy' 12 def __init__(self,name,age,sex,level): 13 self.name=name 14 self.age=age 15 self.sex=sex 16 self.level=level 17 def score(self,stu,num): 18 stu.score=num 19
1 class OldboyPeople: 2 school='Oldboy' 3 class OldboyStudent(OldboyPeople): 4 def __init__(self,name,age,sex): 5 self.name=name 6 self.age=age 7 self.sex=sex 8 self.score=0 9 def choose_course(self): 10 print('%s is choosing course' %self.name) 11 class OldboyTeacher(OldboyPeople): 12 def __init__(self,name,age,sex,level): 13 self.name=name 14 self.age=age 15 self.sex=sex 16 self.level=level 17 def score(self,stu,num): 18 stu.score=num
1 #使用继承,减少人的属性 2 class OldboyPeople: 3 school='Oldboy' 4 def __init__(self,name,age,sex): 5 self.name=name 6 self.age=age 7 self.sex=sex 8 class OldboyStudent(OldboyPeople): 9 #def __init__(self,name,age,sex): 10 # self.name=name 11 # self.age=age 12 # self.sex=sex 13 # self.score=0 14 def choose_course(self): 15 print('%s is choosing course' %self.name) 16 class OldboyTeacher(OldboyPeople): 17 #def __init__(self,name,age,sex,level): 18 # self.name=name 19 # self.age=age 20 # self.sex=sex 21 # self.level=level 22 def score(self,stu,num): 23 stu.score=num 24 stu1= OldboyStudent('andy',18,'male') 25 print(stu1.__dict__) 26 tea1= OldboyTeacher('alex',30,'male') 27 print(tea1.__dict__)
输出:
{'name': 'andy', 'age': 18, 'sex': 'male'}
{'name': 'alex', 'age': 30, 'sex': 'male'}
1 #此时不仅需要继承,还需要派生 2 #如何在子类派生出的新方法中重用父类的功能? 3 #方式一:指名道姓地访问某一个类的函数,该方式需要注意: 4 #1.该方式与继承是没有关系的 5 #2.访问时某一个类的函数,没有自动传值的效果 6 class OldboyPeople: 7 school='Oldboy' 8 def __init__(self,name,age,sex): 9 self.name=name 10 self.age=age 11 self.sex=sex 12 class OldboyStudent(OldboyPeople): 13 def __init__(self,name,age,sex,num=0): 14 OldboyPeople.__init__(self,name,age,sex) 15 self.score=num 16 def choose_course(self): 17 print('%s is choosing course' %self.name) 18 class OldboyTeacher(OldboyPeople): 19 def __init__(self,name,age,sex,level): 20 OldboyPeople.__init__(self,name,age,sex) 21 self.level=level 22 def score(self,stu,num): 23 stu.score=num 24 stu1= OldboyStudent('andy',18,'male') #OldboyStudent.__init__(stu1,'andy',18,'male') 25 print(stu1.__dict__) 26 tea1= OldboyTeacher('alex',30,'male',10) #OldboyTeacher.__init__(tea1,'alex',30,'male') 27 print(tea1.__dict__)
输出:
{'name': 'andy', 'age': 18, 'sex': 'male', 'score': 0}
{'name': 'alex', 'age': 30, 'sex': 'male', 'level': 10}
1 #此时不仅需要继承,还需要派生 2 #如何在子类派生出的新方法中重用父类的功能? 3 #方式二:只能在子类中用 4 #在python2中:super(自己的类名,对象自己) 5 #在python3中:super() 6 #调用super()会得到一个特殊的对象,该特殊的对象时专门用来引用父类中的属性,完全参照mro列表 7 #注意: 8 # 1.该方式与继承严格依赖于继承的mro列表 9 # 2.访问是绑定方法,有自动传值的效果 10 class OldboyPeople: 11 school='Oldboy' 12 def __init__(self,name,age,sex): 13 self.name=name 14 self.age=age 15 self.sex=sex 16 class OldboyStudent(OldboyPeople): 17 def __init__(self,name,age,sex,num=0): 18 #OldboyPeople.__init__(self,name,age,sex) 19 super(OldboyStudent,self).__init__(name,age,sex)#跳过自己的类找父类属性 20 self.score=num 21 def choose_course(self): 22 print('%s is choosing course' %self.name) 23 class OldboyTeacher(OldboyPeople): 24 def __init__(self,name,age,sex,level): 25 super().__init__(name,age,sex) 26 self.level=level 27 def score(self,stu,num): 28 stu.score=num 29 stu1= OldboyStudent('andy',18,'male') #OldboyStudent.__init__(stu1,'andy',18,'male') 30 print(stu1.__dict__) 31 tea1= OldboyTeacher('alex',30,'male',10) #OldboyTeacher.__init__(tea1,'alex',30,'male') 32 print(tea1.__dict__)
输出:
1 #单继承背景下的属性查找顺序:对象-》对象的类-》对象类的父类 2 class Foo: 3 def f1(self): 4 print('Foo.f1') 5 6 def f2(self): 7 print('Foo.f2') 8 self.f1() #obj.f1() 9 10 class Bar(Foo): 11 def f1(self): 12 print('Bar.f1') 13 14 15 obj=Bar() 16 obj.f2() 17 18 Foo.f2 19 Bar.f1
输出:
Foo.f2 Bar.f1