python继承
Posted 玩好人生这场大游戏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python继承相关的知识,希望对你有一定的参考价值。
概念
如果两个或者两个以上的类具有相同的特征【属性】和行为【成员函数】,我们可以抽取一个类出来,在抽取出来的类中声明公共的部分
被抽取出来的类:父类,超类,基类
两个或者两个以上的类:子类,派生类
他们之间的关系:子类继承自父类 父类派生出子类
作用:简化代码,提高了代码的复用性和可维护性
继承的特点:
- 子类对象可以直接访问父类中未私有化的属性
- 子类对象可以调用父类中为私有化的成员函数
- 父类对象不能访问子类特有的属性和成员函数
继承的优缺点:
- 优点:可以简化代码,减少冗余;可提高代码的可维护性;提高代码的安全性;是多态的前提
- 缺点:在继承关系中,耦合性是比较高的【如果修改父类,子类也随之发生改变】
备注:直接上代码了
- 子类:Son类
- 父类:Father类
以下案例均表示Son类继承父类的一些属性和初始化参数构造等。
5个模块:
(1):直接调用父类属性方法
(2):重写父类属性方法
(3):强制调用父类私有属性方法
(4):调用父类的__init__方法
(5):继承父类初始化过程中的参数
(1)调用父类属性方法
代码1.1:
class Father(): def __init__(self): self.a=\'aaa\' def action(self): print(\'调用父类的方法\') class Son(Father): pass son=Son() # 子类Son 继承父类Father的所有属性和方法 son.action() # 调用父类方法 son.a # 调用父类属性
输出结果:
(2)重写父类属性方法
注意:在上面的例子中,子类Son没有属性和action的方法,所以会从父类调用,那我们再来看看,子类Son有自身的属性和方法的结果是怎样的?
上述代码修改为:
class Father(): def __init__(self): self.a=\'aaa\' def action(self): print(\'调用父类的方法\') class Son(Father): def __init__(self): self.a=\'bbb\' def action(self): print(\'子类重写父类的方法\') son=Son() # 子类Son继承父类Father的所有属性和方法 son.action() # 子类Son调用自身的action方法而不是父类的action方法 son.a
输出结果:
这里,子类Son已经重写了父类Father的action的方法,并且子类Son也有初始化,因此,子类会调用自身的action方法和属性。总结:如果子类没有重写父类的方法,当调用该方法的时候,会调用父类的方法,当子类重写了父类的方法,默认是调用自身的方法。
另外,如果子类Son重写了父类Father的方法,如果想调用父类的action方法,可以利用super()
代码2.1:
#如果在重新父类方法后,调用父类的方法 class Father(): def action(self): print(\'调用父类的方法\') class Son(Father): def action(self): super().action() son=Son() son.action()
输出结果:
(3)强制调用父类私有属性方法
如果父类的方法是私有方法,如 def __action(self) 这样的话再去调用就提示没有这个方法,其实编译器是把这个方法的名字改成了 _Father__action(),如果强制调用,可以这样:
代码3.1
class Father(): def __action(self): # 父类的私有方法 print(\'调用父类的方法\') class Son(Father): def action(self): super()._Father__action() son=Son() son.action()
(4)调用父类的__init__方法
如果自己也定义了 __init__ 方法,那么父类的属性是不能直接调用的,比如下面的代码就会报错
代码4.1:
class Father(): def __init__(self): self.a=a class Son(Father): def __init__(self): pass son=Son() print(son.a)
结果报错:
修改方法:可以在 子类的 __init__中调用一下父类的 __init__ 方法,这样就可以调用了
class Father(): def __init__(self): self.a=\'aaa\' class Son(Father): def __init__(self): super().__init__() #也可以用 Father.__init__(self) 这里面的self一定要加上 son=Son() print(son.a)
输出结果:
(5)继承父类初始化过程中的参数
代码5.1:
class Father(): def __init__(self): self.a=1 self.b=2 class Son(Father): def __init__(self): super().__init__() #也可以用 Father.__init__(self) 这里面的self一定要加上 def add(self): return self.a+self.b son=Son() print(son.add())
输出结果:
上述代码中,父类在初始化过程中,直接对a,b分别赋值1,2。子类利用super().__init__()继承了父类的初始化参数a和b,所以子类调用自身的add函数(add函数返回a和b的和)会返回结果值。
再看一下,如果不对父类初始化直接赋值,并且子类在调用父类初始化过程中,增加额外自身需要的初始化参数值。
说明:三个参数a,b,c,其中a,b来自父类初始化参数,c表示子类初始化参数,但又分为两种情况:
1):参数c为初始化默认参数,如下面的5.1代码中Son(1,2),参数1,2分别表示a,b的值,默认为c=10,即等于:Son(1,2,10),表明初始化传参过程中c可以不写
2):显式地将初始化参数c修改为其他值,如下面的5.2代码中Son(1,2,1),参数值1,2,1分别表示a,b,c的值,即显式地将c=1传入
具体代码如5.1 , 5.2所示,对比查看:
代码5.1:
class Father(): def __init__(self,a,b): self.a = a self.b = b def dev(self): return self.a - self.b #调用父类初始化参数a,b并增加额外参数c class Son(Father): def __init__(self,a,b,c=10): # 固定值: 例如默认c=10,也可以显示地将c赋值 Father.__init__(self,a,b) self.c = c def add(self): return self.a+self.b def compare(self): if self.c > (self.a+self.b): return True else: return False son=Son(1,2) # 由于c在初始化过程中默认为10,所以c可以不用显示表达出来 print(son.dev()) # 调用父类dev函数 print(son.add()) # 子类自身add函数 print(son.compare()) # 子类自身compare函数
返回结果:
如果将上述5.1代码中,修改c为其他参数值(非默认值),改成显式地将c值传入
代码5.2:
class Father(): def __init__(self,a,b): self.a = a self.b = b def dev(self): return self.a - self.b #调用父类初始化参数a,b并增加额外参数c class Son(Father): def __init__(self,a,b,c=10): # 固定值: 例如默认c=10,也可以显示地将c赋值 Father.__init__(self,a,b) self.c = c def add(self): return self.a+self.b def compare(self): if self.c > (self.a+self.b): return True else: return False son=Son(1,2,1) # 显示地将c=1传入子类初始化函数 print(son.dev()) # 调用父类dev函数 print(son.add()) # 子类自身add函数 print(son.compare()) # 子类自身compare函数
输出结果:
经典类/新式类继承的区别
多继承时:
- 经典类和新式类在python3里没有任何区别,python3里面都是广度优先;
- 在python2里是有区别的,区别如下:
- 经典类是深度优先
- 新式类是广度优先
- python2 经典类里面不能用super
广度优先/深度优先:
以上是关于python继承的主要内容,如果未能解决你的问题,请参考以下文章