类的继承

梦想的初衷 提交于 2019-11-28 18:17:12

1. 继承介绍

'''
什么是继承:
    ---是一种新建类的方式,继承了一个类,类中的属性和方法就在子类中
    --父类/基类
    --子类/派生类
    --新式类:只要继承了object类,就是新式类,在python3中,默认继承object类
        -python3中:默认继承object
            class A:
                pass
        -python2中,需要显示的指定继承object
    --经典类:没有继承object的类,就是经典类
        -python3中没有经典类
        -python2中才有

'''

class A(object):
    pass

# B继承了A这个类
class B(A):
    pass

# 类的其他内置属性  __名字__
print(B.__dict__)
# 类名
print(B.__name__)
# B的父类
print(B.__bases__)


# 多继承
class A(object):
    pass

class C:
    pass
# B继承了A这个类
class B(A,C):
    pass

# 类的其他内置属性  __名字__
print(B.__dict__)
# 类名
print(B.__name__)
# B的父类
print(B.__bases__)

print(C.__bases__)

2. 利用继承减少代码冗余

class Person:
    school = 'oldboy'

class Teacher(Person):

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

class Student(Person):

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

stu1 = Student('wed',19,'python')
print(stu1.school)

# 问题一:如何重用父类的属性
# 问题二:属性的查找顺序是什么
#     先找对象---》类中找---》父类中找(多继承)---》报错
# 问题三:如何重用父类的方法

class Person(object):
    school = 'oldboy'
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Teacher(Person):
    pass

class Student(Person):
    pass

# 类实例化会自动调用__init__如果类中没有,去父类中找
# stu1 = Student()   # 报错,因为父类中必须传两个参数
stu1 = Student('nick',18)
print(stu1.__dict__)


# 多层继承
class A:
    a = 'AAAA'
class B(A):
    # a = 'BBB'
    pass
class C(B):
    # a = 'CCC'
    pass
class D(C):
    # a = 'DDD'
    pass

d = D()
print(d.a)


#多继承的多层
class A:
    # a="AAAA"
    pass
class B:
    # a="BBB"
    pass

class C:
    a="CCC"
    pass

class D(A,B,C):
    # a = "DDD"
    pass

d=D()
print(d.a)

3. 菱形问题

# 继承的菱形问题:新式类和经典类的查找顺序是不一样的
# 新式类的查找顺序:广度优先
# 经典类的查找顺序:深度优先
class G(object):
    a = 'GGG'
    # pass
class F(G):
    # a = "FFF"
    pass
class E(G):
    # a = "EEE"
    pass
class D(G):
    # a = "DDD"
    pass
class C(F):
    # a="CCC"
    pass
class B(E):
    # a="BBB"
    pass
class A(B,C,D):
    # a="AAAA"
    pass

a=A()
print(a.a)

# mro列表,继承顺序查找列表(只有在新式类中有)
print(A.mro())
print(A.__mro__)

#继承的菱形问题(显示的都继承一个类,不是object类):新式类和经典类的查找顺序是不一样的
#新式类(py3中全是新式类):广度优先---从左侧开始,一直往上找,找到菱形的顶点结束(不包括菱形顶点),继续下一个继承的父类往上找,找到菱形的顶点结束(不包括菱形顶点),最后找到菱形顶点
#经典类(只有py2中才有):深度优先---从左侧开始,一直往上找,找到菱形的顶点结束(包括菱形顶点)继续下一个继承的父类往上找,找到菱形的顶点结束(不包含菱形定点)

#不出现菱形问题:正常查找

4. 重用父类方法

# 继承重用父类方法

# object写与不写,在py3中没有区别,
# 有的人在py3中这么写,为了向下兼容
# 方式一:指名道姓的使用,跟继承没有关系
class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Person:
    school = 'oldboy'

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

    def study(self):
        print('study')


class Teacher(Person):

    def __init__(self, name, age, level):
        A.__init__(self, name, age)
        # self.name = name
        # self.age = age
        self.level = level


class Student(Person):

    def __init__(self, name, age, course):
        # 如何重用父类的__init__方法
        # 指名道姓的使用Person的__init__方法
        Person.__init__(self, name, age)
        self.course = course

    def study(self):
        Person.study(self)
        print(f'{self.name}在学习')


stu1 = Student('wed', 19, 'python')
print(stu1.school)
stu1.study()


# 方式二:通过super关键字,跟继承有关系
class Person(object):
    school = 'oldboy'

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

    def study(self):
        print('study')


class Student(Person):
    school = 'yyyy'

    def __init__(self, name, age, course):
        # super()会按照mro列表拿到父类对象
        #super()相当于得到了一个特殊对象,第一个参数不需要传,调用绑定方法,会把自己传过去
        # 对象来调用绑定方法,不需要传递第一个参数(self)
        super().__init__(name, age)
        # 经典类和新式类
        # 经典类中必须这么写(py3中没有经典类),都用上面那种方式写
        #看到别人这么写:super(类名,对象)  在py3中为了兼容py2
        #在py3中这么写和省略写法完全一样
        #在py2中必须super(Student,self)写
        # super(Student,self).__init__(name,age)
        self.course = course

    def study(self):
        # Person.study(self)
        super().study()


stu1 = Student('wed', 19, 'python')
stu1.school = 'xxx'
print(stu1.school)
stu1.study()

# 总结,有继承关系的时候,通常用super,
# 指名道姓的方式在什么情况下用?
# 1 没有继承关系
# 2 如果继承了多个父类,super是按照mro列表找,现在想指名道姓的用某个父类的某个方法,就需要指名道姓的使用

4.1 super练习

#super练习
# super是按照mro列表找
class A:
    def f1(self):
        print('A.f1')
class B:
    def f1(self):
        print('B.f1')
    def f2(self):
        print('B.f2')
        super().f1()
        # return 'xxxxx'

class C(B,A):
#注意这个顺序,这个顺序报错
# class C(A,B):
    def f1(self):
        print('C.f1')

#C实例化产生一个对象
c=C()
# print(c.f2())
print(C.mro())
c.f2()

5. 回顾绑定方法

class Student:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def study(self):
        print(self.name)
        print('study')
    def chang_name(obj,new_name):
        print('原来的名字是%s'%obj.name)
        obj.name=new_name
        print('修改的名字是%s' % obj.name)

#类来调用对象的绑定方法(写在类中的函数,没加装饰器),有几个参数就需要传几个参数
# Student.__init__(123,'nick',18)   # 报错
#类实例化产生对象,会自动调用__init__完成初始化操作
stu=Student('nick',18)
#对象的绑定方法的特殊之处,会把对象本身当做第一个参数传入
stu.study()
stu2=Student('tank',18)
stu2.study()

# 修改学生姓名
stu=Student('nick',18)
# 方式一
print(stu.name)
stu.name = 'tank'
print(stu.name)
# 方式二
stu.chang_name('amy')
print(stu.name)
# 方式三
Student.chang_name(stu,'wed')
print(stu.name)
# 方式四
# 定义一个函数
def change_name(obj,name):
    # 修改obj对象的name属性
    print('原来的名字是%s' % obj.name)
    obj.name=name
    print('修改的名字是%s' % obj.name)

change_name(stu,'bob')
print(stu.name)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!