一、继承

继承: 子类可以把父类的相关的方法和属性复制一份

# 继承就是在类的后面写上(父类)
# 1. 继承可以把父类的所有的属性和方法获取到
class Father:
    # 类属性 因为他存放在类空间中 同时所有的对象都可以使用这个属性
    name = "老王"

    def dance(self):
        print("广场舞")


class Son(Father):
    pass


son = Son()
son.dance()
print(son.name)
  • 单继承:只有一个父类
# 继承就是在类的后面写上(父类)
# 1. 继承可以把父类的所有的属性和方法获取到
class Father:
    def __init__(self):
        self.name = "老王"

    def dance(self):
        print("广场舞")


class Son(Father):
    pass


son = Son()
son.dance()
father = Father()
print(id(son.name))
print(id(father.name))
  • 多继承:有多个父类
"""
多继承就是有多个父类
1.如果多个父类中有不同的方法和属性就会被子类全部继承
2.如果有多个父类,并且父类中方法或者属性相同,那么就会使用先继承的父类的方法和属性
"""


class Father1:
    name = '老王'

    def dance(self):
        print('广场舞')


class Father2:
    name = '老李'

    def dance(self):
        print('扭秧歌')


class Son(Father1, Father2):
    pass


son = Son()
son.dance()
print(son.name)

多继承:

  • 如果多个父类的方法和属性都不相同
  • 子类会把所有的不相同的方法和属性都继承下来
  • 如果多个父类的方法和属性有相同的情况
  • 子类会按照继承顺序, 先继承(father1, father2) father1的相关的方法和属性

二、子类重写父类的方法和属性

使用: 我们不会单一的只为了继承父类的属性和方法而继承, 子类会进行重写, 把和父类相同的方法名和属性名进行重写

# 继承可以在父类的基础上添加新方法和属性 进而可以省略写和父类相同方法和属性
# 方法的重写: 把和父类相同的方法的名字重新在子类里定义 这个时候我们使用的子类的方法的时候用的就是重写后的方法了
class Father:
    def __init__(self):
        self.name = "老王"

    def dance(self):
        print('广场舞')

    def run(self):
        print("走路")


class Son(Father):
    def __init__(self):
        Father.__init__(self)
        self.name = "小王"

    def sing(self):
        print("唱歌")

    def dance(self):
        print('街舞')


son = Son()
son.dance()
son.run()
son.sing()
print(son.name)

三、子类调用父类的方法

两种方式:

父类名.父类方法()

# 子类调用父类的方法 直接使用父类名 父类方法就可以了

class Father:

    def dance(self):
        print('广场舞')

    def run(self):
        print("走路")


class Son(Father):

    def sing(self):
        print("唱歌")

    def dance(self):
        Father.dance(self)
        print('街舞')


son = Son()
son.dance()
# son.run()
# son.sing()

super().方法名()

# super当继承关系非常复杂的时候, 我们可以使用super()方法
class Father1:
    def dance(self):
        print('广场舞1')


class Father2:
    def dance(self):
        print('广场舞2')


class Son(Father1, Father2):
    def dance(self):
        super().dance()
        print('街舞')


print(Son.__mro__)
son = Son()
son.dance()

mro顺序表

                  类名.mro ==> 得到一个顺序表, 通过这个顺序表就可以获取super的调用情况

class Base:
    def __init__(self):
        print('Base.__init__')


class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')


class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')


class D(Base):
    def __init__(self):
        super().__init__()
        print('D.__init__')


class C(A, D, B):
    def __init__(self):
        super().__init__()
        print('C.__init__')


print(C.__mro__)
c = C()

super的两种使用方式

  • A对象的 super().方法() : 直接从mro顺序表里找相应的方法进行调用,并且A作为起始位置
  • A对象的 super(B,self).方法(): 直接直接从mro顺序表里找相应的方法进行调用,并且B作为起始位置
class Base:
    def __init__(self):
        print('Base.__init__')


class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')


class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')


class C(A, B):
    def __init__(self):
        super(B, self).__init__()
        print('C.__init__')


print(C.__mro__)
c = C()

使用的建议:

复杂的继承关系指的是 发生多层继承的同时又发生了多继承

  • 没有复杂继承管的情况的话 使用
  • 父类名.父类方法()
  • 有负责继承关系使用
  • super()

四、私有属性和私有方法

定义私有属性 是两个下划线开头的属性就是私有属性

私有属性的作用: 确保数据的安全性

  • 子类无法继承 私有属性
  • 在类的外部 无法直接获取 和 修改 私有属性

修改私有属性

  • 在类的内部修改私有属性 私有属性可以在类的内部使用(我们可以通过一个def set_vlaue这样的方法对私有属性就行修改, 同时可以设置数据的验证代码 进而保证数据的符合我们的要求)
  • 私有属性可以在类的内部回去 比如直接定义一个def get_value方法, 就可以获取私有属性
# 私有权限:
# 私有权限可以给属性和方法设置
# 1. 在继承的时候不会被子类获取到, 只能在父类里使用
# 2. 不能在类的外部修改和调用私有属性或者方法
# 3. 设置的方式 两个下划线就是私有权限
class Father:
    def __init__(self):
        self.name = "老王"
        self.__age = 20

    # 私有属性可以在类的内部修改 这样就可以设置相应的条件 进而保证数据的安全性
    def set_value(self, value):
        if 0 < value < 200:
            self.__age = value
        else:
            print("数据不对")

    # 私有权限可以在类的内部获取
    def get_value(self):
        print(self.__age)


father = Father()
print(father.name)
father.set_value("王汪汪")
father.get_value()
# print(father.__little_son)
# class Son(Father):
#     pass
#
#
# son = Son()
# print(son.name)
# print(son.__little_son)

私有方法的使用和私有属性的使用完全一样

class Father:
    def __dance(self):
        print('舞蹈')

    def get_value(self):
        self.__dance()


class Son(Father):
    pass

father = Father()
# 私有方法在类的外部无法直接调用
# father.__dance()
# 私有方法可以在类的内部进行调用
father.get_value()
# 私有方法不可以被继承
son = Son()
son.get_value()
# son.__dance()

五、例题-搬家具

需求

将小于房子剩余面积的家具摆放到房子中

步骤分析

需求涉及两个事物:房子 和 家具,故被案例涉及两个类:房子类 和 家具类。

class House:
    def __init__(self, area, address):
        # 家庭住址
        self.house_address = address
        # 房子面积
        self.house_area = area
        # 空闲面积
        self.free_house_area = area
        # 家具列表
        self.item_list = []

    def add_item(self, item):
        # item家具对象
        # 判断剩余面积是否大于家具面积
        if self.free_house_area >= item.item_area:
            # 如果大于则可以添加家具
            self.item_list.append(item.item_name)
            # 添加完毕以后 家的剩余面积就会发生变化
            self.free_house_area = self.free_house_area - item.item_area
        else:
            # 剩余面积不大于家具面积
            print("面积不足!!!")

    def __str__(self):
        # 描述房子的信息
        return f"房子位于{self.house_address},房子的总面积:{self.house_area}," \
               f"房子的剩余面积:{self.free_house_area},家具有:{self.item_list}"


class Item:
    def __init__(self, name, area):
        # 家具的名字
        self.item_name = name
        # 家具的面积
        self.item_area = area


# 定义房子
house = House(100, "新郑丽园")
# 定义家具a
a = Item("红木沙发", 10)
# 定义家具a
b = Item("红木床", 89)
# 定义家具a
c = Item("红木电视机", 20)

# 把家具添加到家里
house.add_item(a)
print(house)
house.add_item(b)
print(house)
house.add_item(c)
print(house)