python3 继承,接口继承,抽象类,super调用父类的方法,多态


任性插入:

  继承的时候,如果子类中没有初始化函数,但是要去看看父类中有没有初始化函数,再决定子类在实例化的时候要不要传参;

  子类中的方法想要调用父类中的方法,self.方法名;

  子类中的方法想使用类中的其他方法也是加上self.; 

1.面向对象三大特性:

  封装 根据 职责属性方法 封装 到一个抽象的 中;

  继承 实现代码的重用,相同的代码不需要重复的编写;

  多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度;

 补充:

    【转自别人】

 

   

 

继承好处:

   提升代码的重用率:

  有利于代码的管理,在需要改代码的时候,只需要在父类中修改,不需要动子类中的代码。

  单继承和多继承(但是在java中继承只能是单继承,其余的语言不清楚)

class Father(): pass
class Mather(): pass
class Son(Father):##########单继承
    pass
class Daughter(Father,Mather):##########多继承
    pass
View Code

2.什么时候用组合,什么时候用继承?

  (1)当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好;

    比如说一架车子是由不同的组件组合起来的,这样类似的即用组合,把全部的零件组装成一个完整的整体。

  (2)当类之间有很多相同的功能,把这些共同的功能写成父类,子类去继承就可以,用继承比较好;

    比如小猫小狗人都有吃喝拉睡的动作,如果在各自的类中都要写吃喝拉睡的方法,那重复的代码太多,那就可以使用继承,写个动物类中有吃喝拉睡,小猫小狗人调用即可。

3.继承的作用:

  (1)减少重复代码,子类可扩展或者可以修改【但是往往在实践中,该含义意义并不很大,甚至常常是有害的,因为它使得子类与基类出现强耦合。】

  (2)声明某个子类兼容于某基类,定义一个接口类,子类继承接口类,并且在子类实现接口中定义的方法————————————接口继承

  【目的:规范子类,子类实现接口类的中定义的方法,并且不必要实例化】

  【copy来的:接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,

      可一视同仁的处理实现了特定接口的所有对象”一这在程序设计上, 叫做归一化。】————个人感觉意思就是:任何一个子类要调用接口类都必须要实现其定义的方法,

  子类想怎么实现就怎么实现,不关其他任何人的事情,当然子类还可以有属于自己的方法【类似java中的接口。。。。】。

4.继承的MRO顺序:

  在经典类中,没有继承object类

  在新式类中,有继承object类

  在python3中,所有类最顶层父类都是object类,与java类似,如果定义类的时候没有写出父类,则object类就是其直接父类。

  现在的问题是,如果多个父类中包含了同名的方法,此时会发生什么呢?此时排在前面的父类中的方法会“遮蔽”排在后面的父类中的同名方法。

class Father(object):#######新式类
    pass
class Mather():##########经典类
    pass
View Code

但是,这一切在python3出现之后发生了变化,因为在python3里面创建的都是新式类。

不管它俩的变化,我们目前关注的是两种类在多继承状态下查找“方法”的顺序。

经典类:深度查找

新式类:广度查找

 

经典类顺序(深度):F---D---B--A后F---E---C---A

新式类顺序(广度):F--D---B(不找基类)后F---E--C--A

但是在新式类中,对于程序猿定义的每一个类,python会计 算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表

为了实现继承.python会在MRO列表上从左到右开始查找基类,当到找到第一个匹配这个属生的类为止,

而这个MRO列表的构造是通过一个C3线性化算法来实现的。它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

(1)子类会先于父类被检查【类似作用域】

(2)多个父类会根据它们在列表中的顺序被检查

(3)如果对下一个类存在两个合法的选择,选择第一个父类;

新式类可以直接通过 类名.__mro__ 的方式获取类的 MRO,也可以通过 类名.mro() 的形式。

class Father(): print("这个是父亲") class Mather(): print("这个是母亲") class Son(Father):##########单继承
    print("这个是儿子") class Son1(Father,Mather):##########多继承
    print("这个是儿子") class Daughter(Father,Mather):##########多继承
    print("这个是女儿") print(Son1.__mro__) print(Daughter.__mro__) ###################
这个是父亲 这个是母亲 这个是儿子 这个是儿子 这个是女儿 (<class '__main__.Son1'>, <class '__main__.Father'>, <class '__main__.Mather'>, <class 'object'>) (<class '__main__.Daughter'>, <class '__main__.Father'>, <class '__main__.Mather'>, <class 'object'>)
View Code

 重写:

  子类包含与父类同名的方法的现象被称为方法重写(Override),也被称为方法覆盖。可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法。

   通过使用未绑定方法即可在子类中再次调用父类中被重写的方法

 【在通过类名调用实例方法时,Python 不会为实例方法的第一个参数 self 自动绑定参数值,而是需要程序显式绑定第一个参数 self。这种机制被称为未绑定方法。】

class Fruit():
    def name(self):
        print('我是所有水果的父类')

class Apple(Fruit):
    def name(self):
        print('我重写了Fruit的name方法——苹果')

    def run_fruit(self):
        # 直接执行name方法,将会掉哟个子类重写之后的name方法
        self.name()
        #   使用类名调用实例方法(未绑定方法)调用父类被重写的方法
        Fruit.name(self)

apple=Apple()
apple.name()
apple.run_fruit()


##########################
我重写了Fruit的name方法——苹果
我重写了Fruit的name方法——苹果
我是所有水果的父类
View Code

5.接口继承

接口是一组功能的入口,要调用某一组功能,需要通过接口来进行调用,而不需要关注这组功能是如何实现的,要的只是结果。

在类里,接口是提取了一群类共同的函数,可以把接口当做一个函数的集合。

正如2所说的,接口父类只是定义有什么方法,但是并不具体实现其方法体,当有子类去继承该父类时候,需要具体去实现这些方法体。

 1 class Animal():  2     def eat(self):  3         pass
 4     def read(self):  5         pass
 6 
 7 class Cat(Animal):  8     def eat(self,name):  9         print('%s 在吃鱼' %name) 10 
11     def read(self,name): 12        print('%s 在读书' %name) 13 a=Animal() 14 print(a.eat()) 15 c=Cat() 16 c.eat("周周") 17 c.eat("小周周") 18 
19 ############
20 
21 None 22 周周 在吃鱼 23 小周周 在吃鱼
View Code

6.抽象类

  抽象类的本质上也是类,但是抽象类只能够被继承,不能进行实例化,也就是说可以当父类,但是不能生成对象。

  抽象类介于接口和归一化中间,用于实现接口的归一化

  当子类继承抽象类的时候,如果抽象类定义了抽象方法,那么子类必须要定义同名的方法。即父类限制:

    1、子类必须要有父类的方法

    2、子类实现的方法必须跟父类的方法的名字一样

  python的抽象类通过abc模块实现。

import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def eat(self): pass @abc.abstractmethod def read(self): pass

class Cat(Animal): def eat(self,name): print('%s 在吃鱼' %name) def read(self,name): print('%s 在读书' %name) ###a=Animal() #####注意注意,不能实例化,否则报错 #####TypeError: Can't instantiate abstract class Animal with abstract methods eat, read
c=Cat() c.eat("周周") c.eat("小周周") ######
周周 在吃鱼 小周周 在吃鱼
View Code

 7.super方法调用父类的数据属性和函数属性

  Python 要求,如果子类重写了父类的构造方法,那么子类的构造方法必须调用父类的构造方法。

  子类的构造方法调用父类的构造方法有两种方式:

  1. 使用未绑定方法,这种方式很容易理解。因为构造方法也是实例方法,当然可以通过这种方式来调用。
  2. 使用 super() 函数调用父类的构造方法。

  【注意,当子类继承多个父类是,super() 函数只能用来调用第一个父类的构造方法,而其它父类的构造方法只能使用未绑定的方式调用。】

  在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用,使用super().__init__()或parentClassName.__init__()或者其他方式。【书写的方式有点点不同】

重写了就只会调用子类中的重写的方法;

'''
重写:子类和父类里面有相同的函数名
扩展:子类有父类里面没有的方法
'''

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

    def msg(self):
        print('我是父类!!!!')

class Son(Parent):
    def __init__(self,name,age,job):
        super().__init__(name,age)
        self.job=job

    def msg(self):
        print('我是子类============')

    def job_msg(self):
        print('我的名字是:{0},年龄{1},工作是:{2}'.format(self.name,self.age,self.job))


son=Son('jack','25','python测试工程师')
son.msg()
son.job_msg()


##########################
我是子类============
我的名字是:jack,年龄25,工作是:python测试工程师
View Code
class Vehicle1: Country='China'
    def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('开动啦') print('开动啦') class Subway(Vehicle1): def __init__(self,name,speed,load,power,line): ###使用父类的数据属性
           # Vehicle.__init__(self,name,speed,load,power)###如果是使用父类的名字,那在修改后,子类的就很麻烦修改
            super().__init__(name,speed,load,power)###super就不用修改咯
           #super(__class__,self).__init__(name,speed,load,power)###三种方式均可以
           #super(Subway,self).__init__(name,speed,load,power)
            self.line=line def show_info(self): print(self.name,self.speed,self.load,self.power,self.line) def run(self): ###调用父类的方法
            # Vehicle.run(self)
 super().run() print('%s %s 号线,开动啦' %(self.name,self.line)) line2=Subway('成都地铁','100km/h',1000000000,'',2) line2.show_info() line2.run() print(line13.__class__) ########
成都地铁 100km/h 1000000000 电 2 开动啦 成都地铁 2 号线,开动啦 <class '__main__.Subway'>
View Code

 super()是一个特殊的函数,将父类跟子类关联起来,super()._init_(),,其作用是将子类包含父类的所有属性。

为避免多继承报错,使用不定长参数,接受参数

__author__ = 'Administrator'
class Parent(object):
    def __init__(self,name):
        print("Parent的__init__方法开始!!调用")
        self.name=name
        print("Parent的__init__方法结束==调用")

class Son1(Parent):
    def __init__(self,name,age):
        print("Son1的__init__方法开始调用")
        self.age=age
        Parent.__init__(self,name)
        print("Son1的__init__方法结束调用")

class Son2(Parent):
    def __init__(self,name,gender):
        print("Son2的__init__方法开始调用")
        self.gender=gender
        Parent.__init__(self,name)
        print("Son2的__init__方法结束调用")

class Grandson(Son1,Son2):
    def __init__(self,name,age,gender):
        print("Grandson的__init__方法开始调用")
        Son1.__init__(self,name,age)
        Son2.__init__(self,name,gender)
        print("Grandson的__init__方法结束调用")

grandson=Grandson("孙子",18,"")

############################
Grandson的__init__方法开始调用
Son1的__init__方法开始调用
Parent的__init__方法开始!!调用
Parent的__init__方法结束==调用
Son1的__init__方法结束调用
Son2的__init__方法开始调用
Parent的__init__方法开始!!调用
Parent的__init__方法结束==调用
Son2的__init__方法结束调用
Grandson的__init__方法结束调用
View Code
___author__ = 'Administrator'
class Parent(object):
    def __init__(self,name,*args,**kargs):
        print("Parent的__init__方法开始!!调用")
        self.name=name
        print("Parent的__init__方法结束==调用")

class Son1(Parent):
    def __init__(self,name,age,*args,**kargs):
        print("Son1的__init__方法开始调用")
        self.age=age
        super().__init__(name,*args,**kargs)
        print("Son1的__init__方法结束调用")

class Son2(Parent):
    def __init__(self,name,gender,*args,**kargs):
        print("Son2的__init__方法开始调用")
        self.gender=gender
        super().__init__(self,name,*args,**kargs)
        print("Son2的__init__方法结束调用")

class Grandson(Son1,Son2):
    def __init__(self,name,age,gender):
        print("Grandson的__init__方法开始调用")
        super().__init__(name,age,gender)
        print("Grandson的__init__方法结束调用")

grandson=Grandson("孙子",18,"")


##############################

Grandson的__init__方法开始调用
Son1的__init__方法开始调用
Son2的__init__方法开始调用
Parent的__init__方法开始!!调用
Parent的__init__方法结束==调用
Son2的__init__方法结束调用
Son1的__init__方法结束调用
Grandson的__init__方法结束调用
View Code 
___author__ = 'Administrator'
class Parent(object):
    def __init__(self,name,*args,**kargs):
        print("Parent的__init__方法开始!!调用")
        self.name=name
        print("Parent的__init__方法结束==调用")

class Son1(Parent):
    def __init__(self,name,age,*args,**kargs):
        print("Son1的__init__方法开始调用")
        self.age=age
        super().__init__(name,*args,**kargs)
        print("Son1的__init__方法结束调用")

class Son2(Parent):
    def __init__(self,name,gender,*args,**kargs):
        print("Son2的__init__方法开始调用")
        self.gender=gender
        super().__init__(self,name,*args,**kargs)
        print("Son2的__init__方法结束调用")

class Grandson(Son1,Son2):
    def __init__(self,name,age,gender):
        print("Grandson的__init__方法开始调用")
        super().__init__(name,age,gender)
        print("Grandson的__init__方法结束调用")
print(Grandson.__mro__)

grandson=Grandson("孙子",18,"")

#################################
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的__init__方法开始调用
Son1的__init__方法开始调用
Son2的__init__方法开始调用
Parent的__init__方法开始!!调用
Parent的__init__方法结束==调用
Son2的__init__方法结束调用
Son1的__init__方法结束调用
Grandson的__init__方法结束调用
View Code

  通过父类名调用的时候,parent调用了两次;

  使用super的时候,parent 只是执行了一次;

___author__ = 'Administrator'
class Parent(object):
    def __init__(self,name):
        print("Parent的__init__方法开始!!调用")
        self.name=name
        print("Parent的__init__方法结束==调用")

class Son(Parent):
    def __init__(self,name,age):
        print("Son的__init__方法开始调用")
        self.age=age
        super().__init__(name)# 单继承不能提供全部参数
        print("Son的__init__方法结束调用")


class Grandson(Son):
    def __init__(self,name,age,gender):
        print("Grandson的__init__方法开始调用")
        super().__init__(name,age)# 单继承不能提供全部参数
        print("Grandson的__init__方法结束调用")

grandson=Grandson("孙子",18,"")


###########################
Grandson的__init__方法开始调用
Son的__init__方法开始调用
Parent的__init__方法开始!!调用
Parent的__init__方法结束==调用
Son的__init__方法结束调用
Grandson的__init__方法结束调用
View Code

 【转自别人:】

总结:

  1. super().__init__相对于类名.__init__,在单继承上用法基本无差;
  2. 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果;
  3. 多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错;
  4. 单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错,
  5. 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因。
  6. 不知道是不是重复了:具有两个父类的属性和方法,如果两个父类具有同名方法的时候,就近原则(__init__也是)。

8.

  在调用父类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数;

  重写父类方法——————————对于父类的方法,如果有不符合子类想要做的事情,可以对父类的方法进行重写,重写时要与父类的方法同名,这样python将不会考虑父类的方法,而只是关注子类定义的相应的方法。

9.

  isinstance(obj,cls)判断是否obj是否是类 cls 的对象

   issubclass(sub, super)判断sub类是否是 super 类的派生类

1 class Person():
 2     pass
 3 class Man(Person):
 4     pass
 5 p=Person()
 6 m=Man()
 7 print(isinstance(p,Person))
 8 print(isinstance(m,Person))#####因为有了继承的关系
 9 print(isinstance(p,Man))
10 print(issubclass(Man,Person))
11 
12 ######################
13 True
14 True
15 False
16 True
View Code

10.多态:同一个方法在不同的类中最终呈现出不同的效果,即为多态。

class Fruit():
    def name(self):
        print('我是水果')

class Apple(Fruit):
    def name(self):
        print('我是苹果')


Fruit().name()
Apple().name()
View Code


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM