一、组合

自定义类的对象作为另一个类的属性。

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

t1 = Teacher('Bob',20)
print(type(t1.name), type(t1.age))

class Student:
    # 学生可以有 老师 属性
    def __init__(self, name, age, teacher):
        self.name = name
        self.age = age
        # 自定义类的对象作为类的属性:组合
        self.teacher = teacher
    # 创建一个学生

# 创建一个学生
stu = Student('Bob', 18, t1)
print(stu.__dict__)

# 学生的老师年龄和姓名
print(stu.name)
print(stu.teacher)
print(stu.teacher.name)
print(stu.teacher.age)

二、继承

将所有共同的属性与方法抽离出,形成父类

父类是多个有共同点的普通类抽离共有属性与方法形成的类

class People:
    def __init__(self,name):
        self.name = name

    def eat(self):
        print(self.name + '在吃饭')

class Student(People):
    identify = '学生'
    # def __init__(self, name):
    #     self.name = name
    #
    # def eat(self):
    #     print(self.name + '在吃饭')
student = Student('Bob')
student.eat()

class Teacher(People):
    # def __init__(self, name):
    #     self.name = name
    #
    # def eat(self):
    #     print(self.name + '在吃饭')
    pass
teacher = Teacher('Ben')
teacher.eat()

class Leader(People):
    # def __init__(self, name):
    #     self.name = name
    #
    # def eat(self):
    #     print(self.name + '在吃饭')
    pass
leader = Leader('Yang')
leader.eat()

print(Student.identify)  # 只是自身类拥有
# print(Teacher.identify)  # 父类没有,其他类就没有

print(Leader.__bases__)  # (<class '__main__.People'>,)


继承的语法:

class  类名(父类名):

        pass

class A:
    pass
print(A.__bases__)  # object

2.1、继承关系

1、父类所有未封装的属性和方法,子类都能访问

2、父类所有封装的属性和方法,子类都不能访问

        -- 在外界通过子类和子类对象,都不能访问

        -- 在子类内部也不能访问

class Sup:
    __num = 10

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

    @property
    def name(self):
        print(self)
        return self.__name

    @classmethod
    def __c_fn(cls):
        print(cls,'c fn')

    def __o_fn(self):
        print(self.name, 'o fn')


class Sub(Sup):
    def test(self):
        print(self)
        print(self.__name)

# Sub.__c_fn()  # 无法访问父类的私有属性
sub = Sub('sss')
print(sub.name)
# sub.test()  # 无法访问

2.2、有继承关系下的属性查找顺序

有继承关系下的属性查找顺序
    1、优先找自身,自身没有再找父类
    2、父类没有继续往父类的父类找
    3、一直找到最顶级的父类,如果没有就报错

2.3、方法的重写

先写子类,抽离出父类

先写父类,派生出子类

class Sup:
    num = 10

    def test(self):
        print('test sup')

class Sub(Sup):
    num = 100

    # 先写好父类的方法,由于父类方法的功能不满足子类需求,
    # 子类可以重写父类方法:方法名与父类相同,自定义方法的实现体
    def test(self):
        print('test sub')
print(Sub.num)  # 100
Sub().test()  # test sub

2.4、方法的重用

有时,单纯的继承父类不能满足需求,但是重写又要用到父类,因此可以通过super()关键字进行方法重用

class Sup:
    def test(self):
        print('sup>>>',self)
        print('test sup')

class Sub(Sup):
    def test(self):
        # python2中写法
        # super(Sub, self).test()
        # python3中简化写法
        super().test()
        print('sub>>>',self)
        print('test sub')
Sub().test()  # 既执行父类,又执行子类

__init__结合super()使用:

# 人类:只需要初始化 - name
# 老师: 要初始化 - name salary
# 学生: 要初始化 - name grade
class People:
    def test(self):
        print(self)

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

class Teacher(People):
    # 有继承关系下,只要名字相同,即使参数不同,还是属于同一个方法
    def test(self, num):
        super().test()
        print(num)
    # 默认父级的__init__可以被继承过来,
    # 但是会出现子类对象的属性比父类多
    def __init__(self,name,salary):
        super().__init__(name)  # 父级有的共性功能通过super()交给父级做
        self.salary = salary  # 子类特有的自己来完成
Teacher('Bob',20000).test(10)

# 使用的时候,还是要使用自己的带参数的,不能使用父类不带参的
# (本质名字相同就是一个,优先查找自己的)
# Teacher('Bob',20000).test()  # test() missing 1 required positional argument: 'num'

重点:super() 可以得到调用父级功能的对象,调用者还是子类对象
    -- super()只能在子类的方法中使用
    -- super()本质 super(子类类名, 当前对象)
    -- super().父类普通方法 | super().__init__() | super()能调用父类所有可继承方法

了解:

-- java中存在真正的方法的重用
def fn():
    pass
def fn(num):
    pass
# fn()调用不传参时调用第一个fn
# fn(10)调用传入一个参数时调用第二个fn

2.5、多继承

2.5.1、简单的多继承

属性的查找顺序:优先找自己的,如果没有,按照继承先后查找父级

通过  类.mro()可以查看继承顺序

class A:
    name = 'A'
    num = 10

class B:
    name = 'B'
    count = 100

# 子类可以继承所有父类的所有可继承属性
class C(A, B):  # 自己 => A => B
    # name = 'C'
    pass

print(C.num)
print(C.count)
print(C.name)
# 打印属性查找的顺序
print(C.mro())

2.5.2、复杂多继承

python基础——18(面向对象2)

class A:
    name = "A"
class B(A):
    name = "B"
class C:
    name = "C"
class D(C):
    name = "D"
class E(B, D):  # 先将B的所有父级们找完再找D的分支
    name = "E"
print(E.mro())  # E => B => A => D => C

2.5.3、菱形继承

python基础——18(面向对象2)

 python2中深度优先,即A先找B>C>G>D>E>F,在查找第一个分支时就将菱形的头G查找了

 python3中广度优先,即A>B>C>D>E>F>G,菱形的头在所有分支查找结束后再被查找

class G: name = "G"
class C(G): pass
class B(C): pass
class E(G): pass
class D(E): name = "D"
class F(G): pass
class A(B, D, F): pass
print(A.mro())

 经典类:python2中才有,没有继承任何类的类

 新式类:python2中直接或间接继承object的类,python3中所定义的所有类

 

相关文章: