面向对象
Python 是一种广泛使用的解释型、高级编程、通用型编程语言,它以其简洁、易读以及面向对象的特性而闻名。面向对象编程(Object-Oriented Programming, OOP)是一种编程范式,它使用“对象”来设计应用程序和计算机程序。在面向对象的程序设计中,我们定义了一组类(class),这些类描述了具有属性和方法(也称为成员函数)的对象。
接下来让我们了解了解类的概念:
类的定义
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
类的构造
比如一只小猫,是不是有四条腿、两个眼睛,这是小猫的属性。那一只小猫它的叫声是不是”喵喵“呐,这是小猫的一直特征行为。那么我们在构造一个类时,也可以将其分成两个部分构造:属性和方法。在 Python 中,使用class 关键字来定义类,类中的函数称为方法。
类的定义格式如下图所示:
我们来尝试构造一个类:
定义一个Student类用于打印学生的成绩
先定义一个class:
class Student: #定义类的时候首字母大写
eye = 2 #学生有两只眼睛,这是他的属性
接下来,我们来初始化一个方法,打印学生成绩要有学生名和成绩,那我们来定义它的参数:
class Student:
# 构造方法 在类被定义的使用就会使用
def __init__(self, n, s): #初始化方法
# self 类中的变量 全类可用
# 类中的属性
self.name = n #初始化变量
self.score = s
#方法
def print_sco(self):
print(f"{self.name}的成绩是{self.score}")
实例化一个类
对于上面构造的Student类,我们来实例化看看:
定义好了Student类,就通过类名+()创建出Student的实例
if __name__ == '__main__':
# 实例化一个类
ls = Student("ls",89)
ls.print_sco()
--------------------------
输出结果:
ls的成绩是89
三大特点
面向对象主要有三大特点:封装、继承和多态。
封装
面向对象编程的一个重要特点就是数据封装。在之前的Student类中,每个实例就拥有各自的name和score这些数据,在类中可以通过函数来访问这些数据,比如打印一个学生的成绩:
既然Student实例本身就拥有这些数据,要访问这些数据,就不需要通过外部函数访问,可直接在Student类的内部定义访问数据的函数,这样就把“数据”给封装起来了。这些封装数据的函数是和Student类本身是关联起来的,称之为类的方法。
所以,当我们将完整的类创建完成之后,即完成了分装。
私有属性
我们发现在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的name、score属性,比如:
#通过类的变量直接去修改变量值
ls.__score = 99
print(ls.__score)
----------------------
输出结果:
99
这样就会让代码变得不安全。
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,只有内部可以访问,外部不能访问,比如:
class Student:
def __init__(self, n, s):
self.name = n
# 私有变量 可以在类的内部去处理 安全一点 不能在外部直接去修改这个值
self.__score = s
继承和多态
继承
在OOP程序设计中,当定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
如,先定义一个名为Animal的class,有一个run()方法可以直接打印:
class Animal(object):
def __init__(self, leg, height):
self.leg = leg
self.height = height
def run(self):
print("Animal is run")
当需要编写Dog和Cat类时,就可以直接从Animal类继承:
# 在括号里面写入父类的名称
class Dog(Animal):
def __init__(self, leg, height, bark):
# self.leg = leg 可以不这样重复编写
# self.height = height
# 使用父类的初始化方法
super().__init__(leg, height) #继承父类的属性
self.bark = bark
def eat_shit(self): #子类独有的方法
print("dog can eat shit")
pass
对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
继承的作用
继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:
if __name__ == '__main__':
snoopy = Dog(3, 1.2, "wangwang")
snoopy.run()
-----------------------
输出结果:
Animal is run
当然,也可以对子类增加一些方法,比如Dog类:
# 父类存在 子类有不同的方式方法 方法的重写
def run(self):
print("dog is running")
当子类和父类都存run()方法时,可以看做子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。输出的就是子类的结果:
snoopy.run()
---------------------
dog is running
这样就获得了继承的另一个好处:多态
多态
多态:父类的引用指向子类的对象
多态的基础条件是继承
接着上面继续定义一个函数:
def run_twice(animal:Animal):
animal.run()
animal.run()
我们可不可以这样调用函数?:
animal = Animal(4,1)
spike = Dog(3,1.2,"wangwang")
run_twice(animal)
run_twice(spike)
在run_twice(animal:Animal)中,animal只是一个变量,只要我们类里面有run的方法就可以传进去
不是只能传animal
可以,这样就体现了我们的多态:多种形态。
总结
本篇介绍了:
- 什么是面向对象
- 类:
- 定义类的时候首字母大写
- 分成两个部分构造:属性和方法。
- 三大特点:封装、继承和多态
- 封装:将完整的类创建完成,包装好
- 继承:
- 子类获得了父类的全部功能
- 当子类和父类具有相同的功能时,父类方法被覆盖
- 多态:父类的引用指向子类的对象,多态的基础条件是继承
们的多态:多种形态。
总结
本篇介绍了:
- 什么是面向对象
- 类:
- 定义类的时候首字母大写
- 分成两个部分构造:属性和方法。
- 三大特点:封装、继承和多态
- 封装:将完整的类创建完成,包装好
- 继承:
- 子类获得了父类的全部功能
- 当子类和父类具有相同的功能时,父类方法被覆盖
- 多态:父类的引用指向子类的对象,多态的基础条件是继承