继承与派生

1,父类与子类,单继承与多继承

'''
继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性
# II:需要注意的是:python支持多继承
'''

# Parent1 和Parent2 是基类/超类
class Parent1(object):
    x=1111

class Parent2(object):
    pass


# Sub1和Sub2 是子类或派生类
class Sub1(Parent1): # 单继承
    pass

class Sub2(Parent1,Parent2): # 多继承
    pass

print(Parent1.__bases__)
print(Parent2.__bases__)
# (<class 'object'>,)

print(Sub1)
print(Sub2)
# <class '__main__.Sub1'>


# 单继承
print(Sub1)
# <class '__main__.Sub1'>

# 多继承
print(Sub2.__bases__)
# (<class '__main__.Parent1'>, <class '__main__.Parent2'>)



# Sub2没有定义x,依然可以从父类取得
print(Sub2.x)
# 111

# III:python的多继承
#     优点:子类可以同时遗传多个父类的属性,最大限度地重用代码
#     缺点:
#         1、违背人的思维习惯:继承表达的是一种什么"是"什么的关系
#         2、代码可读性会变差
#         3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,
#         如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins

2、为何要用继承:用来解决类与类之间代码冗余问题

3,如何实现继承

示例1,先定义People这个类,学生和老师都属于这个类,People的属性可以给Student和Teacher共享
class People:
    school='beijing_university'

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

class Student(People):
    def choose(self):
        print('%s is choosing a course' %self.name)

class Teacher(People):
    def teach(self):
        print('%s is teahing' %self.name)

stu1=Student('mz',12,'female')
print(stu1.school,stu1.name,stu1.age,stu1.sex)

stu1.choose()
# mz is choosing a course


t1=Teacher('eg',22,'male')
t1.teach()
# eg is teahing



# 示例2,在父类的基础上,增加初始值
class People:
    school='beijing_university'

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

class Teacher(People):
    def __init__(self,name,age,sex,subject,salary):
        People.__init__(self,name,age,sex)
        self.subject=subject
        self.salary=salary

    @property
    def teach(self):
        print('%s is teahing' %self.name)

t1=Teacher('mz',12,'female','math',70000)
print(t1.__dict__)
# {'name': 'mz', 'age': 12, 'sex': 'female', 'subject': 'math', 'salary': 70000}

print(t1.name,t1.salary)
# mz 70000


t1.teach
# mz is teahing

4,属性查找

# 示例1
class Foo:
    def f1(self):
        print('from Foo.f1')

    def f2(self):
        print('from Foo.f2')
        self.f1()

class Bar(Foo):
    def f1(self):
        print('from Bar.f1')


# 先找到Bar是否有f2,没有再去父类去找f2,打印出from Foo.f2
# 然后执行f2的self.f1(),同样先在自己的类里去找,没有再去父类去找,这里自己的类就有f1
obj=Bar()
obj.f2()
# from Foo.f2
# from Bar.f1







# 示例2: 执行obj.f2() 就想要得出Foo的值
# 可以隐藏f1,通过f2的接口调出Foo的f1
class Foo:
    def __f1(self):
        print('from Foo.f1')

    def f2(self):
        print('from Foo.f2')
        self.__f1()

class Bar(Foo):
    def f1(self):
        print('from Bar.f1')

#obj=Bar()

#obj.f2()
# from Foo.f2
# from Foo.f1

a=Foo()
Foo._Foo__f1('s')    # 不加参数会报错
# from Foo.f1


5,菱形继承

A类在顶部,B类和C类分别位于其下方,D类在底部将两者连接在一起形成菱形

新式类

新式类(python3):广度优先,会在检索最后一条分支的时候检索大脑袋
(即最后找那个父类)
class A:
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')


class C(A):
    def test(self):
        print('from C')


class D(B,C):
   def test(self):
       print('from D')
     pass

# 类D以及类D的对象访问属性都是参照该类的mro列表
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

# 以上情况下
obj=D()
obj.test()

# 注释掉D类的test
class D(B,C):
#    def test(self):
#        print('from D')
     pass


obj=D()
obj.test()
# from B


# # 总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro


经典类

# 一条路走到黑,即一条分支走完
class A:
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')


class C(A):
    def test(self):
        print('from C')


class D(B,C):
   # def test(self):
   #     print('from D')
     pass

print(D.mro()) D->B->A->C


6,非菱形继承

非菱形继承
如果多继承是非菱形继承,经典类与新式的属性查找顺序一样:
# #    都是一个分支一个分支地找下去,然后最后找object


class E:
    # def test(self):
    #     print('from E')
    pass

class F:
    def test(self):
        print('from F')


class B(E):
    # def test(self):
    #     print('from B')
    pass

class C(F):
    # def test(self):
    #     print('from C')
    pass

class D:
    def test(self):
        print('from D')


class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass

# 新式类
print(A.mro()) # A->B->E->C->F->D->object
#[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]


obj = A()
obj.test() # 结果为:from F

7,Mixins机制(混合功能)

# 多继承的正确打开方式:mixins机制
# mixins机制核心:就是在多继承背景下尽可能地提升多继承的可读性
# ps:让多继承满足人的思维习惯=》什么"是"什么
class Animials:
    pass

class ShitMixin:
    def dog(self):
        print('like to eat shit')

class cats(Animials):
    pass

class dogs(ShitMixin,Animials):
    pass

#PS:Mixin为结尾的类,把它看作为一个单独的功能,提升继承的可读性
#如上,在dogs类里继承的ShitMixin,Animials,就可以很直观的知道继承的是Animials类,增加了ShitMixin类这个功能



# 补充:通常Mixin结果的类放在左边


8,派生




# 例1
class Teacher:
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

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

class Student(Teacher):
    def __init__(self,name,sex,age,height,hobby):
        Teacher.__init__(self,name,sex,age)
        self.height=height
        self.hobby=hobby

    def f1(self):
        print('my name is %s,my hobby is %s' % self.name,self.hobby)

obj1=Teacher('egg','male',33)
print(obj1.__dict__)
# {'name': 'egg', 'sex': 'male', 'age': 33}


obj1.f1()
# my name is egg

obj2=Student('mmz','female',21,170,'sing')
print(obj2.__dict__)
# {'name': 'mmz', 'sex': 'female', 'age': 21, 'height': 170, 'hobby': 'sing'}






# 例2
class Teacher:
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

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

class Student(Teacher):
    def __init__(self,name,sex,age,height,hobby):
        super().__init__(name,sex,age)
        self.height=height
        self.hobby=hobby

    def f1(self):
        print('my name is %s,my hobby is %s' % (self.name,self.hobby))




# super会依据mro的结果,调用发起者后面的类,即Student发起调用,去找父类Teacher,再去找object
print(Student.mro())
# [<class '__main__.Student'>, <class '__main__.Teacher'>, <class 'object'>]

obj2=Student('mmz','female',21,170,'sing')
obj2.f1()
# my name is mmz,my hobby is sing




# 例3
class A:
    def test(self):
        print('from A')
        super().test()

class B:
    def test1(self):
        print('from B')

class C(A,B):
    def test1(self):
        print('from C')

print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
obj=C()
obj.test()   # 会报错
# 依据mro,C发起调用,依次先找A,执行第一行打印'from A',
# 执行第二行super().test(),第二行的test再去找B,B没有test,便报错

# 如果把B的test1改为test,输出的结果为以下
# from A
# from B
#由此可得出,即使肉眼看到的B不是A的父类,在执行的时候也会把他当作父类




9,组合示例

class Course:
    def __init__(self,name,price):
        self.name=name
        self.price=price
    def tell_info(self):
        print('%s %s' % (self.name,self.price))

class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day
    def tell_info(self):
        print('%s %s %s' % (self.year,self.mon,self.day))

class People:
    school='清华'
    def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age

class Teacher(People):
    def __init__(self,name,sex,age,title,year,mon,day):
        super().__init__(name,sex,age)
        self.birth=Date(year,mon,day)
        self.course=[]
    def teach(self):
        print('%s is teach %s' %(self.name,self.course))

math=Course('math','2w')
teacher1=Teacher('mzz','female',23,'camper',2000,6,2)

teacher1.course.append(math)

# 用Date类得出teacher1的出生年月,注意不能直接teacher1.birth()会报错
teacher1.birth.tell_info()

#course定义为列表形式,所以要有循环得出
for obj in teacher1.course:
    obj.tell_info()
# math 2w

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271