zoukankan      html  css  js  c++  java
  • Python面向对象编程-继承

    Python面向对象编程-继承
     
    资料:
    继承操作练习.docx
     
     
    继承 - 语法
    • 单类继承
    class 派生类名(基类名): # 另一种说法:子类名(父类名)
        语句块
     
    • 多类继承
    class 派生类名(类名1, 基类名2, 基类名3, ......):# 另一种说法:子类名(父类名1,父类名2,父类名3, ......)
        语句块
     

    继承 - 属性
    • 子类并不继承父类的私有属性,因此不能访问父类的私有属性。
    • 继承可以层层传递,若当前类的一个属性在当前类内找不到,编译器会查找其父类中是否有,父类的父类中是否有,......,直到查找到最初父类为止。
    • 多类继承的特殊情况
      • 多类继承的层层传递,查找顺序根据从子类-->父类序列的大方向,再在父类序列中从左-->右的顺序查找,直到查找到最初父类为止。
     

    继承 - 方法
    • 子类并不继承父类的私有方法,因此不能访问父类的私有方法。
    • 若子类和父类有相同的方法,则子类只访问自己定义的方法,若要访问父类的同名方法需使用super方法。
      • 比如初始化时,需要访问父类的初始化方法,则:
        • super(子类,self).__init__(参数1,参数2,....)
        • 若是Python3,可以是super().__init__(参数1,参数2,....)
        • Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
    • 继承可以层层传递,若当前类的一个方法在当前类内找不到,编译器会查找其父类中是否有,父类的父类中是否有,......,直到查找到最初父类为止。
    • 多类继承的特殊情况
      • 多类继承的层层传递,查找顺序根据从子类-->父类序列的大方向,再在父类序列中从左-->右的顺序查找,直到查找到最初父类为止。
     
     

    继承 - 初始化
    • 初始化方法1:子类不重写__init__(),此时会自动调用父类的初始化函数。
    • 初始化方法2:子类重写__init__(),系统初始化时将调用子类的初始化函数。
    • 初始化方法3:子类重写__init__(),在其中调用父类的初始化函数,有2种方法调用父类初始化函数:
      • 方法1:super(子类,self).__init__(参数1,参数2,....),或者super().__init__(参数1,参数2,....)
      • 方法2:父类名称.__init__(self,参数1,参数2,...)
     

    用例分析
     
    用例:烤箱用例实现
     
    # 基类
    class OvanEconomy:
        #类属性
        ovan_type = "OVAN_ECONOMY"
     
     
        def __init__(self):
            # 实例属性
            self.bake_time = 0
            self.temperature = 0
     
     
        def set_baketime(self, bake_time):
            self.bake_time = bake_time
     
     
        def get_baketime(self):
            return self.bake_time
     
     
        def set_temperature(self, temperature):
            self.temperature = temperature
     
     
        def get_temperature(self):
            return self.temperature
     
     
        def bake(self):
            print("--------------------------")
            print("       %s"%(self.__class__.ovan_type))
            print("--------------------------")
            print("bake_time: %d s"%(self.bake_time))
            print("temperature:", self.temperature)
            print("BAKEING......")
     
     
     
     
    # 派生类/基类
    class OvanAdvanced(OvanEconomy):
        # 类属性
        ovan_type = "OVAN_ADVANCED"
     
     
        def __init__(self):
            # 实例属性
            super().__init__()
            self.temperature_up = 0
            self.temperature_down = 0
     
     
        # 重载
        def set_temperature(self, temperature_up, temperature_down):
            self.temperature_up = temperature_up
            self.temperature_down = temperature_down
     
     
        # 重载
        def get_temperature(self):
            return self.temperature_up, self.temperature_down
     
     
        # 重载
        def bake(self):
            print("--------------------------")
            print("       %s" % (self.__class__.ovan_type))
            print("--------------------------")
            print("bake_time: %d s"%(self.bake_time))
            print("temperature: UP-%d,  DOWN-%d"%(self.temperature_up, self.temperature_down))
            print("BAKEING......")
     
     
     
     
    # 派生类
    class OvanAppointment(OvanAdvanced):
        # 类属性
        ovan_type = "OVAN_APPOINTMENT"
     
     
        def __init__(self):
            # 实例属性
            super().__init__()
            self.appointment_time = 0
     
     
        # 重载
        def set_appointment_time(self, appointment_time):
            self.appointment_time = appointment_time
     
     
        # 重载
        def get_appointment_time(self):
            return self.appointment_time
     
     
        # 重载
        def bake(self):
            print("--------------------------")
            print("       %s" % (self.__class__.ovan_type))
            print("--------------------------")
            print("bake_time: %d s"%(self.bake_time))
            print("appointment_time: run after %d hours" % (self.appointment_time))
            print("temperature: UP-%d,  DOWN-%d"%(self.temperature_up, self.temperature_down))
            print("BAKEING......")
     
     
     
     
    # 派生类
    class OvanWindRotary(OvanAdvanced):
        # 类属性
        ovan_type = "OVAN_WIND_ROTARY"
     
     
        def __init__(self):
            # 实例属性
            super().__init__()
            self.wind_rotary_flag = False
     
     
        # 新增
        def on_wind_rotary(self):
            self.wind_rotary_flag = True
     
     
        # 新增
        def off_wind_rotary(self):
            self.wind_rotary_flag = False
     
     
        # 重载
        def bake(self):
            print("--------------------------")
            print("       %s" % (self.__class__.ovan_type))
            print("--------------------------")
            print("bake_time: %d s"%(self.bake_time))
            print("temperature: UP-%d,  DOWN-%d"%(self.temperature_up, self.temperature_down))
            if self.wind_rotary_flag:
                print("BAKEING WITH WIND ROTARY......")
            else:
                print("BAKEING......")
     
     
     
     
     
     
    # 测试1:高级烤箱
    ovan_advanced = OvanAdvanced()
    ovan_advanced.set_baketime(100)
    ovan_advanced.set_temperature(100, 200)
    ovan_advanced.bake()
     
     
    # 测试2:高级烤箱+预约功能
    ovan_appointment = OvanAppointment()
    ovan_appointment.set_baketime(100)
    ovan_appointment.set_appointment_time(5)
    ovan_appointment.set_temperature(100, 200)
    ovan_appointment.bake()
     
     
    # 测试3:高级烤箱+热风旋转烤
    ovan_windrotary = OvanWindRotary()
    ovan_windrotary.set_baketime(100)
    ovan_windrotary.set_temperature(100, 200)
    ovan_windrotary.on_wind_rotary()
    ovan_windrotary.bake()
     
    输出
    --------------------------
           OVAN_ADVANCED
    --------------------------
    bake_time: 100 s
    temperature: UP-100,  DOWN-200
    BAKEING......
    --------------------------
           OVAN_APPOINTMENT
    --------------------------
    bake_time: 100 s
    appointment_time: run after 5 hours
    temperature: UP-100,  DOWN-200
    BAKEING......
    --------------------------
           OVAN_WIND_ROTARY
    --------------------------
    bake_time: 100 s
    temperature: UP-100,  DOWN-200
    BAKEING WITH WIND ROTARY......
     
     
     

    一些问题说明
     
    用例1:对于类公有属性
    • 子类中未定义父类同名的类公有属性,则子类实例访问的是父类定义和赋值的类公有属性
    • 子类中定义了与父类同名的类公有属性,则子类实例访问的是自己定义的类公有属性,父类定义的类公有属性依然存在,需要使用父类名访问。
     
    # 基类
    class OvanEconomy:
        #类公有属性
        #ovan_type = "OVAN_ECONOMY"
     
     
    # 派生类/基类
    class OvanAdvanced(OvanEconomy):
        # 子类定义的和父类同名的类公有属性
        ovan_type = "OVAN_ADVANCED"
     
     
    # 测试1:屏蔽子类定义的ovan_type后访问该属性
    #ovan_type = "OVAN_ADVANCED"
    print("测试1:")
    print("ovan_advanced.ovan_type:", ovan_advanced.ovan_type)
     
    输出:
    测试1:
    ovan_advanced.ovan_type: OVAN_ECONOMY
     
    # 测试2:开放子类定义的ovan_type后访问该属性
    print("测试2:")
    print("ovan_advanced.ovan_type:", ovan_advanced.ovan_type)
    print("OvanEconomy.ovan_type:", OvanEconomy.ovan_type)
     
    输出:
    测试2:
    ovan_advanced.ovan_type: OVAN_ADVANCED
    OvanEconomy.ovan_type: OVAN_ECONOMY
     
     
    用例2:对于父类的私有类属性和私有用例属性
    • 子类不能继承父类的私有类属性,私有用例属性,因此,理论上也不能访问父类的私有类属性,私有用例属性。
    • 不能访问的原因是父类的私有属性在后台改名了。使用print(dir(父类名))可以查询改名后的私有属性名称,用该名称子类可以访问父类的私有属性。
     
    # 基类
    class OvanEconomy:
        #类属性
        ovan_type = "OVAN_ECONOMY"
        #类私有属性
        __test1 = "TEST1"
     
     
        def __init__(self):
            # 实例属性
            self.bake_time = 0
            #实例私有属性
            self.__test2 = "TEST2"
     
     
     
     
    # 派生类/基类
    class OvanAdvanced(OvanEconomy):
        # 类属性
        ovan_type = "OVAN_ADVANCED"
     
     
        def __init__(self):
            # 实例属性
            self.bake_time = 200
            super().__init__()
     
     
    # 生成实例
    ovan_advanced = OvanAdvanced()
    # 打印实例能访问的属性和方法
    print(dir(ovan_advanced))
    # 访问父类的类私有属性,实例私有属性
    print(ovan_advanced._OvanEconomy__test1, ovan_advanced._OvanEconomy__test2)
     
    输出:
    ['_OvanEconomy__test1', '_OvanEconomy__test2', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bake_time', 'ovan_type']
     
    TEST1 TEST2
     
     
     
    用例3:关于在子类中重写父类方法的一些使用规则 【可选】
    • 若父类的某个方法在子类中被重写,则该方法在父类的其他方法中不要调用(尤其是父类的初始化__init__()),否则容易出错。
     
    以下是出错的例子:
     
    # 基类
    class base_1:
        nick_name = "农场"
     
        #父类初始化
        def __init__(self, city):
            print("父类初始化开始......")
            self.class_type = "base"
            self.__class_id = 0
            # 这里在实际运行中调用是子类重写的同名方法。
            self.produce_id()
            self.city = city
     
     
        def print_id(self):
            print("CLASS %s 's ID: %d"%(self.__class__.__name__, self.__class_id))
     
     
    # 派生类,单继承
    class derived_1(base_1):
        nick_name = "蔬菜基地"
     
        # 初始化重写
        def __init__(self, city):
            print("子类初始化开始......")
            # 采用super调用父类的初始化函数
            super(derived_1, self).__init__(city)
            # 声明子类自身的__class_id
            self.__class_id = 0
            print("子类初始化结束!")
     
     
        # 重写__class_id的打印方法
        def print_id(self):
            print("CLASS %s 's ID: %d"%(self.__class__.__name__, self.__class_id))
     
     
        # 重写__class_id生成方法
        def produce_id(self):
            print("我是子类重写的produce_id()")
            self.__class_id  = random.randint(100000,999999)
     
     
        def test(self):
            print("调用父类的__class_id打印方法打印父类的私有属性:")
            super(derived_1, self).print_id()
     
     
    输出:
    # 单继承用例----------------------------------
    子类初始化开始......
    父类初始化开始......
    我是子类重写的produce_id()
    父类初始化结束!
    子类初始化结束!
    调用父类的__class_id打印方法打印父类的私有属性:
    CLASS derived_1 's ID: 0 # 这个值并未如期望中的改变,因为父类初始化中调用的是子类重写的produce_id方法。
     
     
    分析:父类初始化时调用了produce_id()方法,但是调用的是子类重写的方法,因此父类的用例私有属性__class_id并未更新,实际上该调用生成了子类的__class_id属性。
    如果把子类__init__()改成:
    def __init__(self, city):
    print("子类初始化开始......")
    # 采用super调用父类的初始化函数
    super(derived_1, self).__init__(city)
    """
    # self.class_type = "drived"
    self.__class_id = 0
    """
    self.print_id()
    print("子类初始化结束!")
     
    则最后的输出为:
    # 单继承用例----------------------------------
    子类初始化开始......
    父类初始化开始......
    我是子类重写的produce_id()
    父类初始化结束!
    CLASS derived_1 's ID: 563690  #父类初始化函数调用的子类produce_id()生成了子类的__class_id属性。
    子类初始化结束!
     
     
    用例4:关于多继承中的父类用例,方法,子类用例,方法之间的关系【可选】
    用例描述:子类重写__init__(),并在初始化前调用父类1的__init__(),父类2的__init__()。两者的__init__()都有对用例的私有属性的初始化操作。
     
    # 基类
    class base_1:
        nick_name = "农场"
     
     
        def __init__(self, city):
            print("父类1初始化......")
            self.class_type = "base"
            self.__class_id = 0
            self.produce_id()
            self.city = city
     
            # 该类特有的属性,农场面积(亩)
            self.area = 100
            print("父类1初始化结束!")
     
     
        def produce_id(self):
            self.__class_id = random.randint(100000,999999)
            print("父类1的produce_id()------->", self.__class_id)
     
     
        def print_id(self):
            print("父类1的print_id() --->", self.__class_id)
     
     
    # 基类
    class base_2:
        nick_name = "养殖场"
     
     
        def __init__(self, city):
            print("父类2初始化......")
            self.class_type = "base"
            self.__class_id = 0
            self.produce_id()
            self.city = city
     
            # 该类特有的属性,养殖场牲畜头数
            self.animal = 10000
     
     
            print("父类2初始化结束!")
     
     
        def produce_id(self):
            self.__class_id = random.randint(100000,999999)
            print("父类2的produce_id()------->", self.__class_id)
     
     
        def print_id(self):
            print("父类2的print_id() --->", self.__class_id)
     
     
     
     
    # 派生类,多继承
    class derived_2(base_1, base_2):
        nick_name = "综合基地"
     
     
        # 初始化重写
        def __init__(self, city1, city2):
            print("子类初始化......")
            # 采用父类类名的方式调用父类的初始化函数
            # 父类1初始化
            base_1.__init__(self, city1)
            base_1.print_id(self)
            # 父类2初始化
            base_2.__init__(self, city2)
            base_2.print_id(self)
     
            # 初始化子类属性
            self.class_type = "drived"
            self.__class_id = -1
     
            print("子类初始化结束!")
     
     
        def print_id(self):
            print("子类的print_id() --->", self.__class_id)
     
     
        def test(self):
            self.print_id()
            base_1.print_id(self)
            base_2.print_id(self)
     
     
     
     
    # 多继承用例
    print(" # 多继承用例----------------------------------")
    instance2 = derived_2("上海", "南京")
    print("city: ", instance2.city)
    print("animal: ", instance2.animal)
    print("area: ", instance2.area)
    print("class_type: ", instance2.class_type)
    instance2.test()
     
     
    输出:
    # 多继承用例----------------------------------
    子类初始化......
    父类1初始化......
    父类1的produce_id()-------> 832192
    父类1初始化结束!
    父类1的print_id() ---> 832192
    父类2初始化......
    父类1的produce_id()-------> 791476
    父类2初始化结束!
    父类2的print_id() ---> 0
    子类初始化结束!
    city:  南京
    animal:  10000
    area:  100
    class_type:  drived
    子类的print_id() ---> -1
    父类1的print_id() ---> 791476
    父类2的print_id() ---> 0
     
     
    分析:
    在子类中,通过父类名前缀,可以准确的调用父类的用例公有方法。
    但是,在每个父类各自的方法调用中,若是调用的其他父类,子类的同名方法,则实际调用的未必本身类中定义的方法,有以下2种情况:
    • 情况1:子类没有重写同名方法,则根据子类继承多个父类时,从左至右排序的第一个父类的同名方法。
               如本列中的父类2的__init__()方法中调用的produce_id()方法就来自于父类1,而该方法实际修改的是父类1的私有变量__class_id,因此,调用该方法后,父类
               2的私有变量__class_id并未修正,修正的是父类1的私有变量。
    • 情况2:子类重写同名方法,则调用的是子类重写的方法。
               如本列中,若子类重写了produce_id()方法,则在父类1,父类2的初始化时,调用的都是子类重写的produce_id()方法,修改的将会是子类的私有变量__class_id,此时的输出结果为:
    # 多继承用例----------------------------------
    子类初始化......
    父类1初始化......
    子类的produce_id()-------> 254232
    父类1初始化结束!
    父类1的print_id() ---> 0
    父类2初始化......
    子类的produce_id()-------> 428122
    父类2初始化结束!
    父类2的print_id() ---> 0
    子类初始化结束!
    city:  南京
    animal:  10000
    area:  100
    class_type:  drived
    子类的print_id() ---> -1
    父类1的print_id() ---> 0
    父类2的print_id() ---> 0
     
     

     
     
  • 相关阅读:
    select @@identity的用法
    类的实践
    UVA 1572 SelfAssembly(图论模型+拓扑排序)
    UVA 10562 Undraw the Trees(多叉树的dfs)
    sprintf与sscanf用法举例
    UVA 10129 Play on Words(欧拉回路)
    UVA 816 Abbott's Revenge(bfs)
    递增【二分】
    递增【二分】
    递增【二分】
  • 原文地址:https://www.cnblogs.com/JacquelineQA/p/13835679.html
Copyright © 2011-2022 走看看