Python札记34_继承(inheritance)

浏览: 978

面向对象编程OOP有以下三个特征,本篇札记中主要讨论继承的知识点:

  • 继承
  • 多态
  • 封装

继承

概念

继承inheritance是面向对象设计中一个重要的概念。如果一个类A继承自另一个类B,则称BA的父类或者超类,或者A是B的子类

继承可以使得子类具有父类的属性和方法,不再需要重新编写方法。同时,子类还可以重新定义自己的属性和方法,或者重新写某些方法,即覆盖掉父类的属性和方法。

继承特点

  • Python中所有的类都是object的子类,即所有的类都继承自object
  • 子类继承父类的所有方法和属性
  • 实现代码重用,子类还可以定义自身特有的属性和方法
  • 继承最主要的功能是实现多态,多态的重要性是实现接口的继承性

Python中由于存在Duck Type,接口定义的重要性被降低了,继承的作用也被大大降低。


单继承

单继承就是指只从一个父类那里继承,即只有一个父类。通过一个简单的例子来了解继承:

class A:
pass

class B(A): # B继承自A
pass
B.__base__ # 类的特殊属性__base__:查看一个类的父类

image.png

  • A是父类,B是子类
  • 所有的类都是object的子类,object类不必写出来;如果继承别的类,则必须写出来
  • __ base__属性查看某个类的父类

通过一个例子来真正了解下继承:

import random   # 导入随机模块

class A: # 定义一个A类
def __init__(self, number): # 初始化函数,传入参数number
num = random.randint(1, 101) # 在1到101之间生成一个随机数
if num > number: # 判断传入参数和随机数的大小
print("{} is bigger than number".format(num))
else:
print("{} is smaller than number".format(num))

class B(A): # B继承自A
pass

res = B(50) # 因为B继承了A类,A类需要传入参数,此处直接给B类传入了参数50

image.png

image.png

  • 例子中父类A中增加了初始化函数__init__()
  • 建立实例的时候执行初始化函数
  • B继承了A,也就拿到了初始化函数
  • 当建立res = B(50)实例的时候,执行了父类的初始化函数,就是继承

class Person:  # 定义父类
def __init__(self,name): # 初始化函数,并且传入name参数
self.name = name # self实例的name属性值是name

def height(self,m): # 创建方法height,传入参数m
h = dict((["height", m],)) # dict((["age", 22],)) # 字典的一种生成形式;元组中如果只有一个元素,末尾必须带上逗号
return h

def color(self,n):
return dict((["color", n],))

def age(self,k):
return dict((["age", k],))

class Boy(Person): # Boy继承自Person
def get_name(self): # 定义一个 get_name()方法
return self.name # 返回实例self属性的值

if __name__ == "__main__":
boy = Boy("xiaoming") # 创建实例
print(boy.get_name()) # 调用子类的方法
print(boy.height(180)) # 子类调用父类的方法
print(boy.color("yelloow"))
print(boy.age(25))

结果:

xiaoming
{'height': 180}
{'color': 'yelloow'}
{'age': 25}
  • 子类也是可以有自己的初始化函数:
class Person:  # 定义父类
def __init__(self,name): # 初始化函数
self.name = name # self实例的name属性值是name

def height(self,m): # 创建方法height,传入参数m
h = dict((["height", m],)) # dict((["age", 28],)) # 字典的一种生成形式
return h

def color(self,n):
return dict((["color", n],))

def age(self,k):
return dict((["age", k],))

class Boy(Person): # Boy继承自Person
def __init__(self):
self.name = "Peter"

def get_name(self): # 定义一个 get_name()方法
return self.name # 返回实例self属性的值

if __name__ == "__main__":
boy = Boy("xiaoming") # 创建实例
print(boy.get_name()) # 调用子类的方法
print(boy.height(180)) # 子类调用父类的方法
print(boy.color("yelloow"))
print(boy.age(25))

运行结果报错:

  • 创建实例的时候,传入的参数过多
  • 子类中初始化函数只有一个self,和父类的初始化函数重名
  • 子类继承了父类的初始化函数,导致__init__()方法同时传入两个参数
  • 解决办法:实例化子类不再显示地传入参数。


    image.png

  • 通过上面的例子发现:如果子类中的方法或者属性和父类的重名,即覆盖了父类,则子类不再继承父类的该属性和方法,例如上面的__init__()方法。
  • 子类和父类中同样名称的属性和方法,称之为子类对父类相应部分的重写

调用覆盖的方法

上面的例子中子类重写了父类的某个方法,如果子类还是想使用父类的该方法,how to do it? 对子类进行如下的修改:

  • 直接使用父类
  • 使用super高级方法
class Person:  # 定义父类
def __init__(self,name): # 初始化函数
self.name = name # self实例的name属性值是name

def height(self,m): # 创建方法height,传入参数m
h = dict((["height", m],)) # dict((["age", 28],)) # 字典的一种生成形式
return h

def color(self,n):
return dict((["color", n],))

def age(self,k):
return dict((["age", k],))

class Boy(Person): # Boy继承自Person
# 以下为修改部分
def __init__(self, name): # 初始化函数必须传入name参数
Person.__init__(self, name) # 以类方法的方式调用__init__()方法,也必须带上name参数
# super(Boy, self).__init__(name):super方法更高级
self.real_name = "Peter" # 给子类的实例self增加real_name属性

def get_name(self): # 定义一个 get_name()方法
return self.name # 返回实例self属性的值

if __name__ == "__main__":
boy = Boy("xiaoming") # 创建实例
print(boy.real_name) # 调用子类self实例的real_name属性 :子类
print(boy.get_name()) # 调用子类的方法:父类
print(boy.height(180)) # 子类调用父类的方法
print(boy.color("yelloow"))
print(boy.age(25))
推荐 0
本文由 皮大大 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册