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
     
     

     
     
  • 相关阅读:
    形象理解ERP(转)
    禁用windows server 2008 域密码复杂性要求策略
    How to adding find,filter,remove filter on display method Form
    Windows Server 2008 R2激活工具
    How to using bat command running VS development SSRS report
    Creating Your First Mac AppGetting Started
    Creating Your First Mac AppAdding a Track Object 添加一个 Track 对象
    Creating Your First Mac AppImplementing Action Methods 实现动作方法
    Creating Your First Mac AppReviewing the Code 审查代码
    Creating Your First Mac AppConfiguring the window 设置窗口
  • 原文地址:https://www.cnblogs.com/JacquelineQA/p/13835679.html
Copyright © 2011-2022 走看看