面向对象之继承与派生

一、继承

继承是一种创建新类的方式,在python中,新建的类可以继承一个或者多好个父类,新建的类课称为子类或派生类,父类称为基类或超类。

通过类的内置属性__bases__可以查看类继承的所有父类。

#父类
class People:
    school = 'star'
    country = 'China'

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

#子类
class Teacher(People):
    def change_score(self):
        print(f'{self.name}正在修改分数')


class Student(People):
    def choose_course(self):
        print(f'{self.name}正在选择课程')

stu1 = Student('nick',18,'male')
tea1 = Teacher('Pam',19,'male')


print(Student.__bases__)  #(<class '__main__.People'>,)
print(stu1.name,stu1.school,stu1.country,stu1.age,stu1.sex)  #nick star China 18 male
print(tea1.name,tea1.school,tea1.country,tea1.age,tea1.sex)  #Pam star China 19 male

 

二、继承与抽象

要找出类与类之间的继承关系,需要先抽象,再继承。抽象即总结像是相似之处,总结对象之间的相似之处得到类,总结类与类之间的相似之处就可以得到父类。

 

继承的作用

子类可以继承父类的所有属性,因而继承可以用来解决类与类之间代码的重用性问题。减少代码的冗余。

 

Teacher类中没有定义__init__方法,但是会从父类中找到__init__从而正常实例化。

#子类
class Teacher(People):
    def change_score(self):
        print(f'{self.name}正在修改分数')

 

三、属性查找

对象在查找属性时,先从自己的__dict__中找,未找到,则去子类中找,未找到,再去父类中找。

#查找顺序
class Foo:
    x = 10

class Bar(Foo):
    x = 100 
    pass

obj = Bar()
obj.x = 1000   #给对象添加属性
print(obj.x)   #1000   先从自己的空间找
class Foo:
    x = 10

class Bar(Foo):
    x = 100 
    pass

obj = Bar()

print(obj.x)  #100  去子类找
class Foo:
    x = 10

class Bar(Foo):
    
    pass

obj = Bar()

print(obj.x)  #10 子类没有去父类

 

四、继承的实现原理

MRO是一个简单的所有基类的线性顺序列表。

在python中子类可以同时继承多个父类,经典类与新式类会又不同的MRO,分别对应属性的两种查找方式: 深度优先 和 广度优先

 

 

 

 

 

 

 

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

class C(A, B):
    pass

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

# 去A找,有的话打印,然后super又执行了test,根据mro中查找打印B类中test。
c.test()
#from A.test
#from B.test

 

多继承的情况下造成 “ 砖石继承 ”

# 新式类:
class A(object):
    # def test(self):
    #     print('from A')
    pass

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

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

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

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

# F-->D-->B-->E-->C-->A-->object
# print(F.mro())
obj = F()
obj.test()

 

五、派生与方法重用

子类可以派生自己新的属性,在查找属性时,若子类的方法名与父类相同,优先查找子类然后是父类。

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')
    def func(self):
        print('from Bar.func')

bar_obj = Bar()
bar_obj.f1()   #from Bar.f1
bar_obj.func()   #from Bar.func
bar_obj.f2()  #from Foo.f2  from Bar.f1    对象————>Bar————>Foo

 

子类中的新属性在__init__内的代码和父类代码重复,解决方法:

方法一:

直接调用某一个类的函数

#子类
class Teacher(People):
    def __init__(self,name,age,sex,sal):
        People.__init__(self,name,age,sex)  #调用的是函数,需要几个参数就要传入几个参数
        self.sal = sal

    def change_score(self):
        print(f'{self.name}正在修改分数')

 

方法二:

调用super() 方法会得到一个特殊对象,该对象专门引用父类属性,且严格按照MRO规定顺序查找

#子类
class Teacher(People):
    def __init__(self,name,age,sex,sal):
        super().__init__(name,age,sex)  #调用绑定方法,自动传入self
        self.sal = sal

    def change_score(self):
        print(f'{self.name}正在修改分数')

注意使用规范:在python2 中 :super( 自己的类名,self )

                         在python3 中 :super( )

 

 

类的分类:

新式类:凡是继承 object 的类或子类都是新式类。

              在python3 中,所有的类都默认继承object。

经典类:在python2中,才会有经典类与新式类之分。

              在python2中,凡是没有继承 object  的类,都是经典类。

 

class User(object):
    pass

class User:  # (<class 'object'>,)
    x = 10
    pass


class Sub(User):
    pass


print(User.__dict__)

print(object)

 

 

posted @ 2019-11-26 15:27  小猪皮蛋  阅读(122)  评论(0编辑  收藏  举报