面向对象编程(二)

一.什么是继承

      1. 继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类

      2.python中继承的特点:

         1).子类可以遗传/重用父类的属性

         2).python中一个子类可以同时继承多个父类

         3).在继承背景下去说,python中的类分为两种:新式类,经典类

              新式类:但凡继承了object的类,以及该类的子类,都是新式类,在python3中一个类即便是没有显式地继承任何类,默认就会                             继承object, 即python3中所有的类都是新式类

              经典类:没有继承object的类,以及该类的子类,都是经典类,在python2中才区分新式类与经典类,在python2中一个类如果没                            有显式地继承任何类,也不会继承object类

      3.为何要用继承

           减少类与类之间代码冗余

      4.如何用继承     

class Parent1():
    pass

class Parent2():
    pass

class Sub1(Parent1):
    pass

class Sub2(Parent1,Parent2):
    pass

print(Parent1.__bases__)
print(Parent2.__bases__)
print(Sub1.__bases__)
print(Sub2.__bases__)

class Parent1():
    xxx=333
    
class Sub1(Parent1):
    pass

obj=Sub1()
# obj.xxx=222
print(obj.xxx)

# 问题:
# 1 子类如何重用父类的属性
# 2 在继承背景下,属性查找的优先级
# 3 新式类与经典类在属性查找上的区别

 二.  属性查找

     1.在单继承背景下的属性查找优先级:对象-->对象所在的类-->父类-->父类的父类......

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

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

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


b=Bar()
b.f2()

"""
Foo.f2
Foo.f1
"""

     2.在多继承背景下属性查找的优先级:

         如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)此时属性的查找优先级是:对象->对象的类->按            照从左往右的顺序一个分支一个分支的找下去       

# 第四层:
class G:
    # x = 'G'
    pass

# 第三层
class E(G):
    # x = 'E'
    pass

class F:
    # x = 'F'
    pass

# 第二层
class B(E):
    # x = 'B'
    pass

class C(F):
    # x = 'C'
    pass

class D:
    # x = 'D'
    pass

# 第一层
class A(B, C, D):
    # x = 'A'
    pass

obj = A()
# obj.x = 111
# print(obj.x)
print(A.mro())
"""
<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>

"""

    3.菱形继承问题

        新式类:广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类

        经典类:深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类 

class G(object):
    # x = 'G'
    pass

# 第三层
class E(G):
    # x = 'E'
    pass

class F(G):
    # x = 'F'
    pass

# 第二层
class B(E):
    # x = 'B'
    pass

class C(F):
    # x = 'C'
    pass

class D(G):
    # x = 'D'
    pass

# 第一层
class A(B, C, D):
    # x = 'A'
    pass


obj=A()
# obj.x=111
print(obj.x)
#新式类(广度优先): obj->A->B->E->C-F->D->G->object
#经典类(深度优先): obj->A->B->E->G->C-F->D

    python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,结果是print(A.mro())

三.子类中调用父类的方法

       1.方法一:指名道姓地引用某一个类中的函数,即父类名.父类方法()

          总结:1.与继承无关 2.访问是类的函数,没有自动传值的效果      

class OldboyPeople:
    school = 'Oldboy'

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

class OldboyStudent(OldboyPeople):
    def __init__(self, name, age, sex, score=0):
        OldboyPeople.__init__(self,name,age,sex)
        self.score = score

    def choose_course(self):
        print('%s choosing course' % self.name)

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

    def score(self,stu,num):
        stu.score=num


stu1=OldboyStudent('刘二蛋',38,'male')
print(stu1.__dict__)

tea1=OldboyTeacher('egon',18,'male',10)
print(tea1.__dict__)

        2.方法二:super() 必须在子类中用

           在python2中:super(自己的类名,自己的对象)

           在python3中:super()

           调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,!!!完全参照mro列表!!!!

           总结:1.严格依赖继承的mro列表 2.访问是绑定方法,有自动传值的效果  

class OldboyPeople:
    school = 'Oldboy'

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

class OldboyStudent(OldboyPeople):
    def __init__(self, name, age, sex, score=0):
        super(OldboyStudent,self).__init__(name,age,sex)
        self.score = score

    def choose_course(self):
        print('%s choosing course' % self.name)

class OldboyTeacher(OldboyPeople):
    def __init__(self,name,age,sex,level):
        super().__init__(name,age,sex)
        self.level=level

    def score(self,stu,num):
        stu.score=num


stu1=OldboyStudent('刘二蛋',38,'male')
print(stu1.__dict__)

tea1=OldboyTeacher('egon',18,'male',10)
print(tea1.__dict__)

     强调:两者使用哪一种都可以,但最好不要混合使用  即使没有直接继承关系,super()仍然会按照mro继续往后找

#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:
    def test(self):
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
c.test() #打印结果:from B


print(C.mro())
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

指名道姓与super()的区别

#指名道姓
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        A.__init__(self)


class C(A):
    def __init__(self):
        print('C的构造方法')
        A.__init__(self)


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        B.__init__(self)
        C.__init__(self)

    pass
f1=D() #A.__init__被重复调用
'''
D的构造方法
B的构造方法
A的构造方法
C的构造方法
A的构造方法
'''

#使用super()
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        super(B,self).__init__()


class C(A):
    def __init__(self):
        print('C的构造方法')
        super(C,self).__init__()


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        super(D,self).__init__()

f1=D() #super()会基于mro列表,往后找

'''
D的构造方法
B的构造方法
C的构造方法
A的构造方法
'''

 当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

      

          

      

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值