面向对象之继承
一.继承
1.什么是继承
在程序中继承是一种新建子类的方式,新创建的类称之为子类\派生类,被继承的类称之为父类\基类\超类
继承描述的一种遗传关系,子类可以重用父类的属性
2.为何用继承?
减少类与类之间代码冗余的问题
3.如何继承
先抽象再继承
在Python中继承的特点?单继承&多继承
class Parent1(object):
pass
class Parent2:
pass
class Sub1(Parent1):
pass
class Sub2(Parent2):
pass
print(Parent1.__bases__)
print(Parent2.__bases__)
python2与python3在继承上的区别
新式类:但凡继承object类的子类,以及该子类的子子类,...都称之为新式类
经典类:没有继承object类的子类,以及该子类的子子类,...都称之为经典类
只有在Python2中才区分新式类与经典类
二.基于继承解决类与类代码冗余问题
在子类派生的新功能中如何重用父类的功能:
方式一:指名道姓地访问某一个类中的函数,与继承无关
class OldboyPeople: school = 'Oldboy' def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender print(OldboyPeople.__init__) class OldboyPeople(OldboyPeople): def choose_course(self): print('%s is choosing course'%self.name) class OldboyTeacher(OldboyPeople): # tea, 'egon', 18, 'male', 10, 3000 def __init__(self, name, age, gender,level,salary): # self.name = name # self.age = age # self.gender = gender OldboyPeople.__init__(self, name, age, gender) self.level=level self.salary=salary def score(self,stu,num): stu.num=num print('老师%s给学生%s打分%s' %(self.name,stu.name,num)) # stu=OldboyStudent('kevin',38,'male') #__init___(stu1,'kevin',38,'male') # print(stu.__dict__) tea=OldboyTeacher('egon',18,'male',10,3000) #__init___(tea,'egon',18,'male',10,3000) print(tea.__dict__) # print(stu.school) # print(tea.school)
三. 在单继承背景下属性的查找
在单继承背景下,无论是新式类还是经典类属性查找顺序都一样
先obj->父类->...
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() #obj.f1() class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2() 在多继承背景下,如果一个子类继承了多个分支,但是多个分支没有汇聚到一个非常object类,无论是新式类还是经典类查找顺序都一样,会按照从左到右的顺序一个分支一个分支的查找下去
在多个继承背景下,如果一个子类继承了多个分支,但是多个分支最终汇聚到一个非object类(菱形继承问题)
新式类:广度优先查找:obj->A->B->E->C->F->D->G->object
经典类:深度优先查找:obj->A->B->E->G->C->F->D
四.super方法
在子类派生出的新功能中如何重用父类的功能:
方式一:指名道姓访问某一个类中的函数,与继承无关
方式二:super(OldboyTeacher,self),在python3中super可以不停传参,调用该函数会得到一个特殊的对象,该对象是专门用来访问父类中属性,
强调:super会严格参照类的mro列表依次查找属性
#A没有继承B, class A: def test(self): print('A.test') super().test() class B: def test(self): print('from B') class C(A,B): pass c=C() c.test() print(C.mro())
作业:
1、类的属性和对象的属性有什么区别?
类的属性是类里的对象共有的,对象的属性是对象特有的.
2、面向过程编程与面向对象编程的区别与应用场景?
面向过程可以把复杂的问题拆分,简单化流程化,适用于扩展性要求低的应用场景,如登录界面,面向对象编程,适用于对拓展性要求高的场景,如对战游戏.
3、类和对象在内存中是如何保存的。
类是直接执行代码,将产生的名称存入名称空间, 对象是先产生一个空的对象 然后运行__init__函数 将这个对象以及额外的参数组装后传给该函数,
4、什么是绑定到对象的方法,、如何定义,如何调用,给谁用?有什么特性
类中的功能函数,就是该类中对象的绑定方法,
class 类名:
def 函数名(self):
pass
p2.函数名()
给对象用
特殊:在使用绑定方法时,不需要关系self参数 会自动将这个对象本身传进来
对象用绑定方法是 最后执行的还是类中的那个函数
5、如下示例, 请用面向对象的形式优化以下代码
在没有学习类这个概念时,数据与功能是分离的,如下
def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
conn.execute(sql)
return xxx
def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
conn.call_proc(sql)
return xxx
# 每次调用都需要重复传入一堆参数
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')
class MySQLHandler: def __init__(self,host,port,db,charset='utf8'): self.host=host self.port=port self.db=db self.charset=charset self.conn=connect(self.host,self.port,self.db,self.charset) def exc1(self,sql): return self.conn.execute(sql) def exc2(self,sql): return self.conn.call_proc(sql) obj=MySQLHandler('127.0.0.1',3306,'db1') obj.exc1('select * from tb1;') obj.exc2('存储过程的名字')
6、下面这段代码的输出结果将是什么?请解释。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
1,1,1
1,2,1
3,2,3
7、多重继承的执行顺序,请解答以下输出结果是什么?并解释。
class A(object):
def __init__(self):
print('A')
super(A, self).__init__()
class B(object):
def __init__(self):
print('B')
super(B, self).__init__()
class C(A):
def __init__(self):
print('C')
super(C, self).__init__()
class D(A):
def __init__(self):
print('D')
super(D, self).__init__()
class E(B, C):
def __init__(self):
print('E')
super(E, self).__init__()
class F(C, B, D):
def __init__(self):
print('F')
super(F, self).__init__()
class G(D, B):
def __init__(self):
print('G')
super(G, self).__init__()
if __name__ == '__main__':
g = G()
f = F()
G D A B
F C B D A
8、什么是新式类,什么是经典类,二者有什么区别?什么是深度优先,什么是广度优先?在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类.
在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
当继承关系为菱形结构时(即一个子类继承了多个分支,且分支最后汇聚到一个非object类时),查找顺序经典类深度优先,新式类广度优先.
深度优先:一条路走到黑,按照从左往右一个分支一个分支的找下去,
广度优先:从左往右,依次运行,当查找到到汇聚的类时,返回上一子类,进入下一个分支进行查找,当汇聚的父类的分支子类全被查找过以后,查找该父类,继续从左往右依次查找.
9、用面向对象的形式编写一个老师类, 老师有特征:编号、姓名、性别、年龄、等级、工资,老师类中有功能
1、生成老师唯一编号的功能,可以用hashlib对当前时间加上老师的所有信息进行校验得到一个hash值来作为老师的编号
def create_id(self):
pass
2、获取老师所有信息
def tell_info(self):
pass
3、将老师对象序列化保存到文件里,文件名即老师的编号,提示功能如下
def save(self):
with open('老师的编号','wb') as f:
pickle.dump(self,f)
4、从文件夹中取出存储老师对象的文件,然后反序列化出老师对象,提示功能如下
def get_obj_by_id(self,id):
return pickle.load(open(id,'rb'))
10、按照定义老师的方式,再定义一个学生类
11、抽象老师类与学生类得到父类,用继承的方式减少代码冗余
12、基于面向对象设计一个对战游戏并使用继承优化代码,参考博客
http://www.cnblogs.com/linhaifeng/articles/7340497.html#_label1