目录
一、面向对象特征
上篇文章我们说到,面向对象编程有三个特性:封装、继承、多态
1、什么是封装
面向对象的程序设计中,某个类把所需要的数据(也可以说是类的属性)和对数据的操作(也可以说是类的行为或方法)全部都封装在类中,分别称为类的成员变量和方法(或成员函数)。这种把成员变量和成员函数封装在一起的编程特性称为封装
2、什么是继承
继承是指可以使用现有类的几乎所有功能(私有属性和私有方法无法继承),并在无需重新编写原来的类的情况下对这些功能进行扩展
3、什么是多态
多态指的是一类事物有多种形态。如序列类型有多种形态:字符串,列表,元组;动物有多种形态:猫,狗,猪。Python 中的多态是指具有不同功能的函数可以使用相同的函数(方法)名,这样就可以用一个函数名调用不同的函数。子对象对函数重新赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。也就是说,多态性就是一种调用方式,不同的执行效果
二、封装
封装分为数据封装与方法封装
- 数据封装即把对象的属性具体的值隐藏起来,对外部显示的只是对象的属性名。比如刘泽的名字,钱包里的钱等
- 方法封装即对外只需要通过方法名就能调用方法,而不需要了解具体方法中的细节。比如洗衣机,按洗衣的功能按钮,就能进行洗衣,我们不需要知道这个过程中的原理;在用支付宝进行付款的时候,只需要在用的时候把二维码给收款方或是扫一下收款方提供的二唯码就可以完成支付,不需要知道支付宝的支付接口,以及后台的处理数据的能力等
2.1 封装的作用
封装数据的主要原因是保护隐私;封装方法的主要有因是隔离复杂度
2.2 封装两个层面
第一层面的封装:创建类和对象时,分别创建两者的名称空间。只能通过类名加“.”或者对象.的方式访问里面的名字
第二层面的封装:类中把某些属性和方法隐藏起来,或者定义为私有,只在类的内部使用,在类的外部无法访问,或者留下少量的接口(函数)供外部访问
三、继承
3.1 继承的概念
当我们定义一个class的时候,可以从某个现有的class 继承属性和方法,新的class称为子类,而被继承的class称为基类、父类或超类
- ⽣活中的继承,⼀般指的是⼦⼥继承⽗辈的财产。
- 子女即为子类,父辈即为基类,父类或超类
在python中,object类是所有类的父类。Python3中默认都是继承object,object类是顶级类或基类;其他⼦类叫做派⽣类
# 括号为空,默认继承object
class 派生类名(object):
pass
3.2 继承的特点
- 在Python中,如果父类和子类都重新定义了构造方法
__init__
( ),在进行子类实例化的时候,子类的构造方法不会自动调用父类的构造方法,必须在子类中显示调用 - 如果需要在子类中调用父类的方法:需要以 父类名.方法 这种方式调用,以这种方式调用的时候,注意要传递self参数过去;另一种方法是使用super() ,直接使用 super().xxx
- Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)
- 对于继承关系,子类继承了父类所有的公有属性和方法,可以在子类中通过父类名来调用,而对于私有的属性和方法,子类是不进行继承的,因此在子类中是无法通过父类名来访问的
- Python支持多继承,能够让一个子类有多个父类
- 如果有多个父类,多个父类名之间用逗号隔开,classSub(Super1,Super2)
- 如果子类没有重新定义构造方
__init__
,它会自动调用第一个父类的构造方法,以第一个父类为中心 - 如果子类重新定义了构造方法,需要显示去调用父类的构造方法,此时调用哪个父类的构造方法由你自己决定
3.3 继承的实现
编写一个Teacher(父类)和一个Student(子类),子类继承父类
3.3.1 单继承
一个学生类继承一个老师类,代码实现如下:
# 父类
class Teacher_One(object):
def __init__(self, name_one, love_one):
self.name_one = name_one
self.love_one = love_one
self.__money = 10000 # 私有属性
def get_teacher_one(self):
return f"大家好,我是老师{self.name_one},我喜欢{self.love_one}"
# 私有方法
def __get_money(self):
return f"我是{self.name_one},我有{self.__money}存款"
# 子类
class Student(Teacher_One):
# __init__下面出现黄色波浪线,子类父类都有构造方法,则子类自动覆盖父类的构造方法,或者说不调用父类方法
def __init__(self, name_one, love_one, name_stu): # 要先把父类的参数传进来
# 注意要显示调用父类的构造方法,这样才继承父类,否则就是覆盖父类
Teacher_One.__init__(self, name_one, love_one)
# super().__init__(self, name_one, love_one) # 这个方法和上面的是一样的
self.name_stu = name_stu # 实例化
# 子类当中,调用父类的方法
# Teacher_One.get_teacher_one()
def get_student(self):
return f"大家好,我是{self.name_stu},我的老师是{self.name_one},我学会了{self.love_one}"
if __name__ == '__main__':
# 创建一个学生类对象
student = Student("张三", "羽毛球", "李四")
# 子类的对象可以调用父类的方法(必须是公有方法)
print(student.get_teacher_one())
print(student.get_student())
# print(student.__get_money()) # 私有属性和私有方法不能被继承的
# 运行结果:大家好,我是老师张三,我喜欢羽毛球
# 大家好,我是李四,我的老师是张三,我学会了羽毛球
3.3.2 多继承
一个学生类同是继承两个老师类,代码如下:
# 老师类一
class Teacher_One(object):
def __init__(self, name_one, love_one):
self.name_one = name_one
self.love_one = love_one
self.__money = 10000
def get_teacher_one(self):
return f"大家好,我是老师{self.name_one},我喜欢{self.love_one}"
# 私有方法
def __get_money(self):
return f"我是{self.name_one},我有{self.__money}存款"
# 老师类二
class Teacher_Two(object):
def __init__(self, name_two, love_two):
self.name_two = name_two
self.love_two = love_two
self.__money = 10000
def get_teacher_two(self):
return f"大家好,我是老师{self.name_two},我喜欢{self.love_two}"
# 子类,多继承
class Student(Teacher_One, Teacher_Two):
def __init__(self, name_one, love_one, name_two, love_two, name_stu):
# 注意要显示调用父类的构造方法
Teacher_One.__init__(self, name_one, love_one)
Teacher_Two.__init__(self, name_two, love_two)
self.name_stu = name_stu
def get_student(self):
return f"大家好,我是{self.name_stu},我的老师是{self.name_one},我学会了{self.love_one}\
另一个老师是{self.name_two},又学会了{self.love_two}" # \:续行
# 相当于孙子类,继承了上面的全部的类
# class Student_Two(Student):
# pass
if __name__ == '__main__':
# 创建一个学生类对象
student = Student("张三", "羽毛球", "李四", "网球", "王五")
# 子类的对象可以调用父类的方法
print(student.get_teacher_one())
print(student.get_teacher_two())
print(student.get_student())
# 运行结果:大家好,我是老师张三,我喜欢羽毛球
# 大家好,我是老师李四,我喜欢网球
# 大家好,我是王五,我的老师是张三,我学会了羽毛球 另一个老师是李四,又学会了网球
四、多态
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数
好处:调⽤灵活,有了多态,更容易编写出通⽤的代码,做出通⽤的编程,以适应需求的不断变化!
实现步骤:
- 定义⽗类,并提供公共⽅法
- 定义⼦类,并重写⽗类⽅法
- 传递⼦类对象给调⽤者,可以看到不同⼦类执⾏效果不同
示例:
# 多态,子类的方法名与父类一样,修改父类方法
class Teacher(object):
def get_data(self):
pass
class Student_One(Teacher):
def get_data(self):
return "老师,张三偷吃东西"
class Student_Two(Teacher):
def get_data(self):
return "老师,李四在看小说"
class Main():
def func_demo(self, demo): # 这里的demo就是对象,传入不同的对象结果就不一样
return demo.get_data() # .get_date,必须要和上面的方法一样,否则没法调用
# #创建对象
stu1 = Student_One()
stu2 = Student_Two()
main = Main()
print(main.func_demo(stu1))
print(main.func_demo(stu2))
# 运行结果:老师,张三偷吃东西
# 老师,李四在看小说