Python面向对象编程-继承,,Python面向对象


Python面向对象编程-继承资料:技术图片继承 - 语法单类继承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 = 0self.temperature = 0def set_baketime(self, bake_time):self.bake_time = bake_timedef get_baketime(self):return self.bake_timedef set_temperature(self, temperature):self.temperature = temperaturedef get_temperature(self):return self.temperaturedef 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 = 0self.temperature_down = 0# 重载def set_temperature(self, temperature_up, temperature_down):self.temperature_up = temperature_upself.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 stemperature: UP-100,DOWN-200BAKEING......--------------------------OVAN_APPOINTMENT--------------------------bake_time: 100 sappointment_time: run after 5 hourstemperature: UP-100,DOWN-200BAKEING......--------------------------OVAN_WIND_ROTARY--------------------------bake_time: 100 stemperature: UP-100,DOWN-200BAKEING 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_ADVANCEDOvanEconomy.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 = 200super().__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 = citydef 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_idself.__class_id = 0print("子类初始化结束!")# 重写__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 = 0self.produce_id()self.city = city# 该类特有的属性,农场面积(亩)self.area = 100print("父类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 = 0self.produce_id()self.city = city# 该类特有的属性,养殖场牲畜头数self.animal = 10000print("父类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 = -1print("子类初始化结束!")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("\n\n# 多继承用例----------------------------------")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:10000area:100class_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:10000area:100class_type:drived子类的print_id() ---> -1父类1的print_id() ---> 0父类2的print_id() ---> 0

Python面向对象编程-继承

评论关闭