Python面向对象进阶4之类之间的关系
开始Python的复习!(以前学的忘了好多-_-)
主要参考的是Github上的一个项目:https://github.com/jackfrued/Python-100-Days
文章主要是对该项目中的内容进行学习 穿插一点自己的学习想法等内容~
类之间的关系
is-a 又称为继承或泛化,例如学生和人、手机和电子产品
has-a 通常为关联,例如部门和员工,汽车和引擎。关联关系如果是整体和部分的关系,称为聚合;如整体进一步负责了部分的生命周期,就是最强的关联关系,称之为合成关系。
usa-a 通常称为依赖,例如司机有驾驶的方法,其中的参数使用到了汽车,那么司机和汽车的关系就是依赖。
UML统一建模语言可以把类和类之间的关系用标准化的图形符号描述出来。
利用类之间的关系,可以在已有类的基础上来完成某些操作,也可以在已有类的基础上创建新的类,这些都是代码复用的重要手段。
接下来重点介绍继承和多态来实现代码复用
继承和多态
父类:提供继承信息,也叫超类或基类
子类:得到继承信息,也叫派生类或衍生类
子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法。
定义类时括号里写的就是继承的父类,所有类都继承object类(默认)
class Person(object):
"""人"""
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
print('%s正在愉快的玩耍.' % self._name)
def watch_av(self):
if self._age >= 18:
print('%s正在观看爱情动作片.' % self._name)
else:
print('%s只能观看《熊出没》.' % self._name)
class Student(Person):
"""学生"""
def __init__(self, name, age, grade):
super().__init__(name, age)
self._grade = grade
@property
def grade(self):
return self._grade
@grade.setter
def grade(self, grade):
self._grade = grade
def study(self, course):
print('%s的%s正在学习%s.' % (self._grade, self._name, course))
class Teacher(Person):
"""老师"""
def __init__(self, name, age, title):
super().__init__(name, age)
self._title = title
@property
def title(self):
return self._title
@title.setter
def title(self, title):
self._title = title
def teach(self, course):
print('%s%s正在讲%s.' % (self._name, self._title, course))
def main():
stu = Student('王大锤', 15, '初三')
stu.study('数学')
stu.watch_av()
t = Teacher('骆昊', 38, '砖家')
t.teach('Python程序设计')
t.watch_av()
if __name__ == '__main__':
main()
super函数
super()是用于调用父类(超类)的一个方法,用来解决多重继承问题。直接用类名调用父类方法在使用单继承的时候没有问题。
但如果使用多继承,会涉及到查找顺序、重复调用(钻石继承)等问题。
语法
super(type[, object-or-type])
参数解释:type 语法 ;object-or-type 类,一般是self。
pyhon3中国可以直接使用super().xxx代替super(class, self).xxx
super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象
在菜鸟教程(下方链接)中的笔记中对该方法有更加详细的介绍。
简单总结如下:
- 在继承父类后,如果直接写子类的初始化函数会导致子类无法继承父类的属性。一种方法就是调用未绑定的超类构造方法(我理解就是在子类初始化中调用父类初始化方法)
原理是在调用了一个实例的方法时,该方法的self参数会自动绑定到实例上(称为绑定方法);如果直接调用类的方法,没有实例会被绑定,可以自由提供需要的self参数(未绑定方法)。
另一种方法是使用super函数,原理是它会查找所有的超类,以及超类的超类,知道找到所需的特性为止。
2.super函数最后可以实现的功能是帮助子类继承父类的特性,不需要点明白到底是哪个 可以自己查找 找到自己所需要的。
方法重写和多态
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写。通过方法重写可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不用的子类对象会表现为不同的行为,这种现象称之为多态。简言之就是在原有模板的基础上,发展出了自己的特性。
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
"""宠物"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)
class Cat(Pet):
"""猫"""
def make_voice(self):
print('%s: 喵...喵...' % self._nickname)
def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()
if __name__ == '__main__':
main()
在上面的代码中,我们将Pet
类处理成了一个抽象类,所谓抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc
模块的ABCMeta
元类和abstractmethod
包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,Dog
和Cat
两个子类分别对Pet
类中的make_voice
抽象方法进行了重写并给出了不同的实现版本,当我们在main
函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。