面向对象
学习目标:
-
理解使用对象完成数据组织的思路
生活中数据的组织
学校开学,要求学生填写自己的基础信息,每人发一张白纸,让学生自己填,这种操作场景下,你会发现,学生填的内容呢是各式各样的,由于我们没有统一的规范,所以说这个信息组织起来是非常的混乱,如果改为登记表,打印出来让学生自行填写,整体上来看效果:整洁明了。通过这个生活中的小案例,我们能够体会到对数据的组织是不是至关重要?那么问题来了,现在是信息化的时代,我们很多时候都不再使用纸质的表单来进行信息的记录了,而是转移到电脑系统中。
程序中数据的组织
那么我们想一下,在我们的程序中又如何组织呢?首先我们来看一个反面教材,我们的程序它有非常多的数据类型,那么所以我们组织数据的形式也是多种多样,比如你可以使用字典来去维护学生的信息,你也可以使用字符串去维护,也可以使用列表去维护,那这种形式多种多样就会造成我们信息组织的混乱和不统一。
student_1 ={
"姓名":"周杰轮",
"性别":"男",
"国籍":"中国",
"籍贯":"台湾省",
"年龄":33
}
student_2="我叫林军杰,今年31岁,男的,来自中国山东省"
student_3 =[
"邓紫旗",
"中国",
"北京市",
26,
"女"
]
多种多样就会造成我们信息组织的混乱和不统一,使用变量记录数据太乱了。
如果程序中也和生活中一样,可以设计表格,可以将设计的表格打印出来,可以将打印好的表格供人填写内容,那么数据的组织就非常方便了。
使用对象组织数据
如果我们把步骤分为三步,在生活中是设计表格,打印表格和填写表格,那么对应着在我们程序中就会有设计类,创建对象和对象属性赋值。在我们生活中你去设计一张表格的话,我们在成语中就叫做设计一个类class,我们可以通过 class 这个关键字给上类名,并且在类的内部去定义变量,用变量来去帮助我们去记录数据。
下面分别来看一下:
1. 在程序中设计表格,我们称之为:设计类(class)
class Student:
name = None #记录学生姓名
2.在程序中打印生产表格,我们称之为:创建对象
# 基于类创建对象
stu_1 = Student()
stu_2 = Student()
3.在程序中填写表格,我们称之为:对象属性赋值
stu_1.name = "周杰轮" # 为学生1对象赋予名称属性值
stu_2.name = "林军杰" # 为学生2对象赋予名称属性值
比如我们构建出来的对象,它里面有一个叫做name的变量,为什么会有name呢,就是因为我们在设计类的时候,提供了name变量用来记录学生姓名, 我们在拿到对象之后呢,就可以通过对象变量名的形式,为它赋予具体的值了,看起来是不是和我们生活中的打印表格这种行为还是比较相像的呀!
生活中或是程序中,我们都可以使用设计表格、生产表格、填写表格的形式组织数据。
成员方法
学习目标
-
掌握类的定义和使用语法
-
掌握成员方法的使用
-
掌握self关键字的作用
类的定义和使用
在上一节中,我们简单了解到可以使用类去封装属性,并基于类创建出一个个的对象来使用。
现在我们来看看类的使用语法,如果我们想在程序中去创建一个类的话,首先我们需要通过一个关键字class,通过它就可以定义一个类了,然后在class的后面,我们写上类的名称,以及写上一个我们的老朋友冒号,在冒号下面呢,我们就可以写上类的内容体了,如下格式所示:
class 类名称:
类的属性
类的行为
class是关键字,表示要定义类了
-
类的属性,即定义在类中的变量(成员变量)
-
类的行为,即定义在类中的函数(成员方法)
那么再来看一下,如果你想要拿到类的具体的对象,怎么做?其实也很简单,我们写上类的名称,然后写上一个括号,就表明创建出来了一个具体的类的对象了,那么你可以通过等号赋值在前面通过一个对象去接收它就可以了。创建类对象的语法:
对象 = 类名称()
这是简单的类的定义语法以及创建类对象的语法。
通过语法,其实我们可以知道类里面其实就两类,一个是属性,可以称之为数据,第二类就是行为,我们可以称之为函数了。
类里面包含属性,我们在上节中已经见识过了,那类里面包含行为又是个什么样子的,来让我们看一下。
成员变量和成员方法
来看下面的例子:
class Student:
name = None # 学生的姓名
age = None # 学生的年龄
def say_hi(self):
print(f"Hi大家好,我是{self.name}")
stu = Student()
stu.name="周杰轮"
stu.say_hi() # 输出:Hi大家好,我是周杰轮
可以看出,类中:
不仅可以定义属性用来记录数据
也可以定义函数,用来记录行为 其中:
-
类中定义的属性(变量),我们称之为:成员变量
-
类中定义的行为(函数),我们称之为:成员方法
好,那么从今天开始我们就要改个口了,我们从今天开始定义在类内部的函数,我们就称之为它们叫方法了。
那所以以后我提到函数,大家要明白,函数就是写到类外面的,那么当我在提到方法的时候,同学们要反应过来,我所说的方法指的就是类内部的函数,但以后我们就不会再把类内部的函数叫函数了,而是叫做方法。
成员方法的定义语法
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
def 方法名(self,形参1,...,形参N):
方法体
可以看到,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的。
-
它用来表示类对象自身的意思
-
当我们使用类对象调用方法的是,self会自动被python传入
-
在方法内部,想要访问类的成员变量,必须使用self
def say_hi(self):
print(f"Hi大家好,我是{self.name}")
注意事项
self关键字,尽管在参数列表中,但是传参的时候可以忽略它,比如:
class Student:
name = None
def say_hi(self):
print("He11o大家好")
def say_hi2(self,msg):
print(f"Hello大家好,{msg}")
stu = Student()
stu.say_hi() # 调用的时候无需传参
stu.say_hi2("很高兴认识大家")#调用的时候,需要传msg参数
我们可以看一下来,在我们的类中定义了两个成员方法,那么这两个成员方法一个是一个不带参数的,其实严格来说它有个self,但是这个是自动传的,所以你当它不存在,所以你可以认为它没有定义传入参数。
那第二个它定义了一个 msg 的传入参数。
好,那么你来看一下,当我们调用的时候,第一个这个 say_hi,我们调用它直接给空参就行了,不需要传参。你会发现这个 self 我们压根没有理会它,但是没关系,它可以正常执行。可以看到,在传入参数的时候,self是透明的,可以不用理会它。
类和对象
学习目标
-
掌握使用类描述现实世界事物的思想
-
掌握类和对象的关系
-
理解什么是面向对象
现实世界的事物和类
现实世界的事物也有属性和行为,类也有属性和行为。
使用程序中的类,可以完美的描述现实世界的事物。
好,你再来回到物上面,我们的物,比如说手机,它同样属性的行为一个不少属性是长宽、高重量、厂商型号,行为是打电话、上网和拍照。又或者说我们再换一个物,比如说有一种生物叫做小狗,那它的属性和行为也是一样,不少属性是身高体重品种,行为就是汪汪叫、吃东西和睡觉。
类和对象
你会发现,在现实世界中,无论是人还是物,都可以总结为两个特征:属性和行为。那么,同学们可能会想,我们前面学习的类是否也有属性和行为?
通过对比,我们会发现,使用程序中的类可以完美地描述现实世界中的事物。好的,到这里,同学们可能会想到我们前面学习的通过类创建具体对象的过程,这里可能有些不太理解。为什么呢?我们刚刚不是说类已经能够完美地描述现实世界中的事物了吗?那么,为什么还要创建对象才能使用呢?
基于类创建对象的语法:
对象名 = 类名称()
为什么非要创建对象才能使用呢?
类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作
这种套路,称之为:面向对象编程。
使用类和对象描述现实事物
比如在我们的现实生活中,我们想要生产事物,假设我们要生产一个闹钟,那你在生产之前是不是需要有设计图纸?那图纸中是不是规划了我们闹钟的一些属性,比如说厚度有多少,尺寸有多大,以及规划了他的行为,比如他可以响铃,那么当我们有了设计图纸之后,那才会开足生产线,把闹钟一个个的都生产出来一堆的实体。
在程序中通过类来描述
你可以想象一下,这种行为和我们在编写程序时设计类并创建对象非常相似。例如,我们可以设想一个闹钟类,其中包含属性序列号和价格,以及一个响铃行为。在代码中,我们只需要定义两个成员变量id和price来表示这些属性,然后定义一个成员方法来实现响铃行为。一旦我们完成了这个类的设计,就可以像生产线一样创建许多具体的闹钟对象了
基于类创建对象
我们之前已经接触过这种语法了,通过类的名称加上一对括号,可以实例化一个具体的对象。例如,基于左边的类,我们基于该设计图构建了两个闹钟,即clock1和clock2对象。这种操作是面向对象编程的基本套路,核心是设计类,创建对象并让对象执行具体的工作。因此,面向对象编程的本质就是让对象去执行任务。
这就是面向对象编程:
设计类,基于类创建对象,由对象做具体的工作
构造方法
学习目标:
-
掌握使用构造方法向成员变量赋值
属性(成员变量)的赋值
class Student:
name = None # 名称
age = None # 年龄
tel = None # 手机号
student1 = Student()
student1.name = "周杰轮"
student1.age = 31
student1.te1 = "18012340000"
student2 = Student()
student2.name = "周杰轮"
student2.age = 31
student2.te1 = "18012340000"
上侧代码中,为对象的属性赋值需要依次进行,略显繁琐。
有没有更加高效的方式,能够一行代码就完成呢?
思考:Student()这个括号,能否像函数(方法)那样,通过传参的形式对属性赋值呢?你看这个语法中是不是写上了类的名称,后面又带上了一个括号,那这个括号是不是我们的老朋友了?我们在调用函数或者说方法的时候,就可以通过括号去传参,那我们想一想在构建类对象的时候,我们能否以传参的形式把我们成员变量的值给它传进去?那如果想实现这个需求是可以的,这个需求就需要通过构造方法来去完成了。
即:init()
构造方法
Python类可以使用:init()方法,称之为构造方法。
可以实现:
-
在创建类对象(构造类)的时候,会自动执行。
-
在创建类对象(构造类)的时候,将传入参数自动传递给init方法使用。
比如我们构建一个基础的学生类,并且拥有姓名、年龄和电话三个基础的成员变量。
基于这两个特性,我们在构建类的时候,这个 init 会自动执行,并且我们的参数会自动地提供给这个 init 构造方法去使用。
class Student:
name = None # 可以省略
age = None # 可以省略
tel = None # 可以省略
def _init_(self,name,age,tel):
self.name = name
self.age = age
self.tel = tel
print("student类创建了一个对象")
stu=student("周杰轮",31,"18500006666")
-
构建类时传入的参数会自动提供给init方法
-
构建类的时候init方法会自动执行
构造方法注意事项
重要的事情说三遍,构造方法名称:init , 千万不要忘记init前后都有2个下划线
构造方法也是成员方法,不要忘记在参数列表中提供:self
在构造方法内定义成员变量,需要使用self关键字
# def __init__(self,name,age,tel):
# self.name = name # 名称
# self.age = age # 年龄
# self.tel = tel # 手机号
这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。
可以用下面的代码再练习一遍:
"""
演示类的构造方法
"""
# 演示使用构造方法对成员变量进行赋值
# 构造方法的名称:__init__
class Student:
def __init__(self, name, age ,tel):
self.name = name
self.age = age
self.tel = tel
print("Student类创建了一个类对象")
stu = Student("周杰轮", 31, "18500006666")
print(stu.name)
print(stu.age)
print(stu.tel)
运行结果:
Student类创建了一个类对象
周杰轮
31
18500006666
学生信息录入
开学了有一批学生信息需要录入系统,请设计一个类,记录学生的:
姓名、年龄、地址,这3类信息
请实现:
通过for循环,配合input输入语句,并使用构造方法,完成学生信息的键盘录入
输入完成后,使用print语句,完成信息的输出
当前录入第1位学生信息,总共需录入10位学生信息
请输入学生姓名:周杰轮
请输入学生年龄:31
请输入学生地址:北京
学生1信息录入完成,信息为:【学生姓名:周杰轮,年龄:31,地址:北京】
当前录入第2位学生信息,总共需录入10位学生信息
请输入学生姓名:
其它内置方法
学习目标:
-
掌握几种常用的类内置方法
魔术方法
上文学习的init 构造方法,是Python类内置的方法之一。
这些内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法,我们在上一个视频中所学习的 init 构造方法就是 Python 类内置的方法之一,这些内置的类方法各自有各自特殊的功能,所以这些内置方法我们又把它们称之为叫做魔术方法。那么我们在本小节要学习哪些魔术方法?我们主要学习下面4 个。
这个魔术方法只有这 5 个吗?其实并不是, Python 内置的魔术方法是非常非常多的,二三十个还是有的,但是我们在课堂中就没有把它们一一都讲解,我们只要学习几个比较常见的就可以。
str 字符串方法
那首先来我们开始正式学习他们第一个方法,我们把它们叫做字符串方法。你看一下它的名字里面前面 2 个下划线,后面 2 个下划线,你是否会觉得和我们的构造方法一样,其实在我们的 Python 内部,前面 2 个下划线,后面 2 个下划线包围起来的方法,其实我们都可以把它们称之为叫做魔术方法,这是他们的一个命名的规范。
好,那么这个字符串方法有什么作用?来我们看一段示例的代码,我们定义了一个类Student,并且获取了它的类对象,获取完成之后我们直接 print 这个类对象,又或者把这个类对象转变成字符串去输出,那它的结果是一样的。
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
student=Student("周杰轮",11)
print(student) # 结果:<_main_.student object at0x000002200cFD7040>
print(str(student)) # 结果:<main_.student object at0x000002200cFD7040>
结果其实表示的是我们当前那个对象的内存地址,好,看起来还是比较高大上的,但是内存地址对于我们来说没什么大的作用,我们一般在开发的过程中也不关心对象的内存地址,那所以说我们可以通过str 这个字符串的内置的魔术方法来去控制我们直接输出这个对象,或者说直接把它转换成字符串的行为。
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return f"student类对象,name={self.name},age={self.age}"
student=Student("周杰轮",11)
print(student) # 结果:student类对象,name=周杰轮,age=11
print(str(student)) # 结果:student类对象,name=周杰轮,age=11
-
方法名:str
-
返回值:字符串
-
内容:自行定义
lt 小于符号比较方法
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
stu1 = Student("周杰轮",11)
stu2 = Student("林军杰",13)
print(stu1 < stu2)
直接对2个对象进行比较是不可以的,但是在类中实现lt方法,即可同时完成:小于符号 和 大于符号 2种比较
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __lt__(self,other):
return self.age < other.age
stu1 = Student("周杰轮",11)
stu2 = Student("林军杰",13)
print(stu1 < stu2) # 结果:True
print(stu1 > stu2) # 结果:Falue
le 小于等于比较符号方法
魔术方法:le可用于:<=、>=两种比较运算符上。
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __le__(self,other):
return self.age <= other.age
stu1=Student("周杰轮",11)
stu2=Student("林军杰",13)
print(stu1 <= stu2)#结果:True
print(stu1 >= stu2)#结果:Falue
eq,比较运算符实现方法
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __eq__(self,other):
return self.age == other.age
stu1 = Student("周杰轮",11)
stu2 = Student("林车杰",11)
print(stu1 == stu2) # 结果:True
-
不实现eq方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果。
-
实现了eq方法,就可以按照自己的想法来决定2个对象是否相等了。