python2中面向对象的多继承是,Python中的继承
本文主要分析python面向对象中的继承。作为python的三大特性之一,类继承在我们学习Python时必不可少。使用类继承可以大大减少代码编写的重复。以下细节可以供各位朋友参考。
00-1010一单继承1。继承的基本语法格式如下。2.查看类继承3。继承中的属性和方法4。初始化函数__init__()和超二级继承三级继承。
目录
作为python的三大特性之一,类继承在我们学习python时必不可少。使用类继承可以大大减少代码编写的重复。现在我们来记录一些关于python中类继承的知识点。
类继承包括单继承、多层继承和多重继承。我们先来看看单继承。
一 单继承
# Class继承语法格式,B类继承a类。
A类():
类别属性
分类方法
.
B(A)类:
类别属性
分类方法
.
在单继承的情况下,一般A类不继承其他派生类,只继承基类。因为在python的新类中,一个类默认会继承基类对象,基类对象是顶级类。
1. 继承的基本语法格式如下
班父():
#这是父类。
name1=父亲名
年龄1=父亲年龄
def父_方法(自身):
打印(“我是父亲”)
班级儿子(父亲):
#这是一个子类。
name2=儿子名
年龄2=儿子年龄
定义子方法(自身):
打印(“我是一个孩子”)
if __name__==__main__:
A=父亲()
B=儿子()
#单一继承
打印(B.__class__。__mro__)
# or Son.mro()
print(Son.mro())
如上:定义了一个父类父亲,一个子类儿子,子类儿子继承父类父亲,所有这些都有自己的属性和方法。我们可以通过打印B.__ class__,来检查Son类的继承。__mro __或Son.mro(),如下:.
(class __main__。子,类 __main__。“父亲”,类“对象”)
[class __main__。子,类 __main__。父亲,类对象]
如您所见,子类继承了父类和基类对象。
2. 查看类继承情况
如果一个类继承了另一个类,那么这个类可以调用它继承的类的属性和方法(子类可以调用父类的属性和方法),如下所示
班父():
#这是父类。
name1=父亲名
年龄1=父亲年龄
def父_方法(自身):
打印(“我是父亲”)
班级儿子(父亲):
#这是一个子类。
name2=儿子名
年龄2=儿子年龄
定义子方法(自身):
打印(“我是一个孩子”)
def fun1(自身):
#调用父类属性和方法
打印(自我年龄1
, self.name1)
self.father_method()
if __name__ == __main__:
A = Father()
B = Son()
#单继承
# print(B.__class__.__mro__)
B.fun1()
结果如下:
>>>
father_age father_name
我是父亲
当子类中的属性名方法名和父类中的属性名方法名同名时,在该子类中会覆盖父类的属性名和方法名(重写)。
class Father():#这是父类
name1 = father_name
age1 = father_age
def father_method(self):
print(我是父亲)
class Son(Father):
#这是子类
name1 = son_name
age1 = son_age
def son_method(self):
print(我是孩子)
def father_method(self):
#和父类方法同名,将以子类方法为准
print("与父类方法同名,但是我是子类")
def son_fun1(self):
#调用父类属性
print("子类属性和父类属性同名,以子类为准:", self.name1, self.age1)
if __name__ == __main__:
A = Father()
B = Son()
#单继承
# print(B.__class__.__mro__)
B.father_method()
B.son_fun1()
输出如下:
>>>
与父类方法同名,但是我是子类
子类属性和父类属性同名,以子类为准: son_name son_age
4. 初始化函数__init__()和 super
上面写的子类和父类都是不需要传参数的,而当我们需要给类传参数时,往往都是要初始化的,下面来看看子类继承父类时,参数初始化的几种情况。
子类无新增参数:
class Father():#父类
def __init__(self, name=张三, age=23):
self.name = name
self.age = age
class Son(Father):
#子类
def son_fun1(self):
print(self.name, self.age)
if __name__ == __main__:
B = Son()
B.son_fun1()
输出:
>>>
张三 23
如上,在子类无新增参数时,无需进行__init__ 初始化,直接调用父类的对象属性即可。因为子类Son是继承自父类Father的,所以在调用时会首先去调父类的__init__ 进行初始化
子类有新增参数:
当子类有新增参数时,该怎么初始化呢?先来看看这个对不对
class Father():#父类
def __init__(self, name=张三, age=23):
self.name = name
self.age = age
class Son(Father):
#子类
def __init__(self, height):
self.height = height
def son_fun1(self):
print(self.height)
print(self.name, self.age)
if __name__ == __main__:
B = Son(170)
B.son_fun1()
输出:
>>>
AttributeError: 'Son' object has no attribute 'name'
170
上面子类Son新增了一个height参数,然后用__init__ 进行初始化。但是从输出结果可以看出,height参数是正常打印的,打印name和age参数时就报错:子类Son没有属性’name’,因为这个时候就不会去调用父类的__init__ 进行初始化,而是直接调用子类中的__init__ 进行初始化,这时,子类初始化就会覆盖掉父类的__init__ 初始化,从而报错。
正确的初始化有两种方法,如下:
#方法1def __init__(self, 父类参数1, 父类参数2, ..., 子类参数1, 子类参数2, ...)
父类名.__init__(self, 父类参数1, 父类参数2, ...)
self.子类属性 = 子类属性
class Father():
#父类
def __init__(self, name=张三, age=23):
self.name = name
self.age = age
class Son(Father):
#子类
def __init__(self, name, age, height):
#方法1
Father.__init__(self, name, age)
self.height = height
def son_fun1(self):
print(self.height)
print(self.name, self.age)
if __name__ == __main__:
B = Son(李四, 24, 170)
B.son_fun1()
>>>
175
李四 24
从结果可以看出,调用父类初始化后,结果就正常输出。这是在子类__init__
初始化的时候,调用了Father.__ init __(self, name, age)对父类对象属性进行了初始化。
现在来看看另外一个初始化方法super()
初始化,不过使用super()的时候要注意python的版本,因为python2和python3的使用是不同的,如下
#方法2def __init__(self, 父类参数1, 父类参数2, ..., 子类参数1, 子类参数2, ...):
#python2的super初始化
super(子类名, self).__init__(父类类参数1, 父类参数2, ...)
self.子类属性 = 子类属性
#python3的super初始化
super().__init__(父类类参数1, 父类参数2, ...)
self.子类属性 = 子类属性
class Father():
#父类
def __init__(self, name=张三, age=23):
self.name = name
self.age = age
class Son(Father):
#子类
def __init__(self, name, age, height):
#方法2
#python2的super初始化
super(Son, self).__init__(name, age)
self.height = height
#python3的super初始化
# super().__init__(name, age)
#或者 super(Son, self).__init__(name, age)
def son_fun1(self):
print(self.height)
print(self.name, self.age)
if __name__ == __main__:
B = Son(李四, 24, 175)
B.son_fun1()
结果:
>>>
175
李四 24
上面使用的是super(Son, self).__ init __ (name, age)
来对父类对象属性进行初始化。不过这是要区分python版本的,在python3中使用super(Son, self).__ init__(name, age)或者super().__ init__(name, age)都是可以的,但是在python2的版本中,要使用super(Son, self).__ init__(name, age)来进行初始化,而且父类必须继承object,否则就会报错。
二 多层继承
上面的记录的是单继承,现在来看看多层继承。多层继承:子类继承自多个父类,父类只继承自object
顶级类。
class Father():def __init__(self):
print("enter father")
print("leave father")
def fun(self):
print("这是father")
class Mother():
def __init__(self):
print("enter mother")
print("leave mother")
def fun(self):
print("这是mather")
class Son(Father, Mother):
def __init__(self):
print("enter son")
super().__init__()
print("leave son")
if __name__ == __main__:
B = Son()
B.fun()
print(Son.mro())
输出:
>>>
enter son
enter father
leave father
leave son
这是father
继承关系:
[<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>]
这里有两个父类Father,Mother,一个子类Son,子类Son继承了类Father和Mother,继承顺序是Father在前,Mother在后。从上面输出结果来看,子类初始化过程是先进入子类Son的 __ init __方法,其次调用super(). __init __()进行父类对象属性初始化,最后初始化完成。
从结果可以知道上面super初始化调用的是父类Father的 __ init __方法。
。也可以看出,类Father和类Mother都有一个fun方法(同名),但在子类调用时调的是父类father的fun方法。这是为什么呢?
这里就涉及到super的继承机制,即super会根据MRO机制,从左到右依次调用父类的属性和方法, 当父类中有同属性名,同方法名时,以靠左的那个父类为准。
下面我们把Father和Mother位置换一下,如下:
class Father():def __init__(self):
print("enter father")
print("leave father")
def fun(self):
print("这是father")
class Mother():
def __init__(self):
print("enter mother")
print("leave mother")
def fun(self):
print("这是mather")
class Son(Mother, Father):#这里变动,变换Father和Mother的位置
def __init__(self):
print("enter son")
super().__init__()
print("leave son")
if __name__ == __main__:
B = Son()
B.fun()
print(Son.mro())
结果:
>>>
enter son
enter mother
leave mother
leave son
这是mather
[<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]
继承关系:
>>>
[<class '__main__.Son'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>]
可以看出,当Mother在前时,调用的就是类Mather的初始化方法和fun方法。所以在多层继承时,一定要注意父类的位置顺序。
三 多重继承
其实super的产生就是用来解决多重继承问题的,什么是多重继承呢?即,子类继承多个父类,而父类又继承自其它相同的类,这种又被称为菱形继承或者砖石继承,
如下:
A
/ \
/ \
B C
\ /
\ /
D
先来看看如下的一个菱形继承:
class A():def __init__(self):
print("enter A")
print("leave A")
class B(A):
def __init__(self):
print("enter B")
# super().__init__()
A.__init__(self)
print("leave B")
class C(A):
def __init__(self):
print("enter C")
# super().__init__()
A.__init__(self)
print("leave C")
class D(B, C):
def __init__(self):
print("enter D")
B.__init__(self)
C.__init__(self)
# super().__init__()
print("leave D")
if __name__ == __main__:
d = D()
输出结果:
>>>
enter D
enter B
enter A
leave A
leave B
enter C
enter A
leave A
leave C
leave D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
上面用的是父类名. __ init__ () 来进行子类初始化的,但是从结果来看,类A的初始化方法是被执行了两次的,一次是类B的调用,一次是类C的调用。也可以看出子类D的初始化 __ init __ 调用了B.__ init __() 和C. __init __() 。现在D类继承的父类只有B和C,但是当代码比较复杂,继承的类比较多时,就得的一个一个写,如果类B和类C也是继承自多个类,那它们的初始化方法也得重新写,这样就比较繁琐,也容易出错。
下面来使用super初始化父类看看:
class A():def __init__(self):
print("enter A")
print("leave A")
class B(A):
def __init__(self):
print("enter B")
super().__init__()
print("leave B")
class C(A):
def __init__(self):
print("enter C")
super().__init__()
print("leave C")
class D(B, C):
def __init__(self):
print("enter D")
super().__init__()
print("leave D")
if __name__ == __main__:
d = D()
print(D.mro())
输出结果:
enter D
enter B
enter C
enter A
leave A
leave C
leave B
leave D
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
可以看到输出结果是不一样的,类A的初始化只执行了一次,而且当D类有新增父类时,初始化方法也不用动,从而避免重写初始化方法出错,代码也变得整洁。
这里还是和super的继承机制有关,上面说过当子类继承自多个父类时,super会根据MRO机制,从左到右依次调用父类的属性和方法,而且使用super初始化父类时,会一次性初始化所有的父类,所以上面的类A初始化方法不会被调用两次。
所以在类的多重继承中,一般建议使用super
来初始化父类对象属性。
到此这篇关于详析Python面向对象中的继承的文章就介绍到这了,更多相关Python面向对象继承内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。