类&对象
面向对象编程— “愿有人陪你颠沛流离,如果没有,愿你成为自己的太阳”
在这一节里我们将开始接触 Python 编程的核心思想 —— 面向对象编程
面向对象编程区别于传统的过程式编程,这种方式可以理解为模拟现实世界中的事物,以真实的对象为核心展开来编写代码。
面向对象编程可以理解为模拟现实世界中的一类事物,把这类事物的特征或者功能用代码封装起来,这个封装好的对象就叫做 类 ,依照这个封装好的类,我们就可以重复创建具有相似特征的一类事物。
类就像是一个设计图,这个设计图一旦创建好之后就可以反复使用,比如我们想盖一栋房子,那就用房屋的设计图,如果想造一辆汽车,那就用汽车的设计图。这个设计图就是 类 ,被建造的汽车、房屋叫做 对象 或者 实例 ,使用设计图创建对象的过程叫做 实例化。
想象一下,我们创建一个叫做 “狗狗” 的类,这个类定义了大部分狗都会有的一些特征,比如有四条腿、爱吃肉、会打滚,在此基础上,我们对不同的狗赋予一些特定的属性,比如小明家的狗喜欢接飞盘、小亮家的狗喜欢睡觉、小红家的狗爱洗澡,虽然这三条狗的性格特点不一样,但是他们都属于我们定义好的 “狗狗” 这一类, 提到这三条狗,我们都知道他们有四条腿、爱吃肉、会打滚的特点。
上面的思考方式就是现实生活中的面向对象,编程界里的面向对象编程思维逻辑也是如此。
面向对象编程可以说是 Python 入门的分水岭,理解这个概念可以帮助你更加理解自己的代码编写的意义,可以通过编写代码来解决几乎所有的问题。
类
在上面的描述中我们粗略地了解了类的概念,知道类在面向对象编程中扮演着 “设计图” 或者 “蓝图” 的功能,比如 “汽车”类、“轮船”类、“房屋”类都是现实生活中的类,让我们学习一下如何在编程世界中实现 “类” 的创建。
我们创建一个代表学生的类,要求学生有以下三个特点:有姓名、有年龄、有性别,并且可以进行读书和写字。
这次我会先上代码,然后再进行讲解:
# 使用 class 关键词创建类
class
Student
():# 使用 init 函数初始化姓名、年龄、性别属性
def
__init__
(self
,name,age,gender):self
.name = nameself
.age = ageself
.gender = gender# 自定义一个 read 函数输出命令
def
read
(self
):print
('这位名叫'
+ self
.name + '的同学正在阅读'
)# 自定义一个 write 函数输出命令
def
write
(self
):print
('这位名叫'
+ self
.name + '的同学正在写字'
)上述代码定义一个 Student 学生类。
第一次见到创建类的代码可能会觉得很难理解,不要急,接下来我将详细讲解其中的原理。
① 类的命名
在第二行的代码中:
class
Student
():我们使用了 class 关键字来命名 Student 类,在给类命名的时候要注意名称的首字母需要大写,并且后面需要接一个空括号(括号中是空白的内容)。
② 构造函数
在类里,__init__ 是一种特殊的函数,叫做 构造函数 ,要注意 __init__ 的写法是 init 前后各有两个下划线 ,当我们调用类来创建对象的时候 Python 都会优先调用它,它就像是类的“启动器”,用于在类被调用的时候 为对象设置初始状态。
想象一下你正在绘制一套房子的设计图,设计图的作用是告诉建筑工人如何去盖房子,但是盖房子之前需要提前准备一些物料,比如水泥、钢筋、砖块等,那么 __init__ 方法就好比在设计图中提前规定好建造需要用的资源,建筑队拿到了图纸后就可以按照规定去进行准备。
__init__ 函数规定了类在创建对象时需要传入哪些属性,要注意的是 __init__ 后可以绑定任意多个属性,但是 第一个参数必须是 self 参数,self 参数可以理解为要创建的对象本身,在上面代码的第 4 行中:
def
__init__
(self
,name,age,gender):我先在 __init__ 后面传入了 self 参数,接着传入了 name 和 age 和 gender 三个参数, “建筑队” 后面在使用这个 “设计图” 的时候需要按照规定依次提供这三个参数。
在定义好待传入的参数之后,需要将待传参数赋予给类的内部属性,在上面代码的第 5 行到 第 7 行:
self
.name = nameself
.age = ageself
.gender = gender使用 self.name = name 将外部传入的 name 参数,赋值给类里的 name 变量,在定义完成后,用户传入的 name 参数将会以 self.name 的形式存储在类里,方便在后面调用这个参数的时候使用。后面的 age 和 gender 参数同理。
当然,属性变量也可以是默认值,比如我设定好这个学生类都是属于三班的,可以在 __init__ 初始化时直接进行指定,比如这样:
def
__init__
(self
,name,age,gender):self
.name = nameself
.age = ageself
.gender = genderself
.class = '三班'
③ 定义方法
在 Python 中,函数也可以称之为 “方法”,两者意义相同,在完成类的初始化后,我们可以定义一些方法来完成我们想要的目的。
想象我们正在使用一台洗衣机洗衣服,这台洗衣机是用设计图制造的,这台洗衣机是一个对象,那么洗衣机上的选择按钮、启动按钮可以理解为类中的方法。当我们按下按钮时它会执行对应的功能,比如清洗、烘干等。
在上面代码的第 9 行到第 15 行中:
# 自定义一个 read 函数输出命令
def
read
(self
):print
('这位名叫'
+ self
.name + '的同学正在阅读'
)# 自定义一个 write 函数输出命令
def
write
(self
):print
('这位名叫'
+ self
.name + '的同学正在写字'
)我们定义了两个方法,分别让学生这个类执行读书和写字两个功能,在这里使用 print 函数输出一段话作为示意,在这段话中,调用了我们在 __init__ 函数中初始化的 self.name 变量。结果会根据用户调用类时传入的姓名来生成。
在低版本的 Python 中,如 Python2.7 版本,类的创建需要做一些细微的调整,在空白括号内包含单词 object ,该版本的原代码的第一行需要改成如下所示:
class
Student
(object
):对象
在上面教程中的提到了对象,对象也叫做实例。我们使用类作为设计图建造的对象也可以称作实例化,还是引用上面代码的例子:
# 使用 class 关键词创建类
class
Student
():# 使用 init 函数初始化姓名、年龄、性别属性
def
__init__
(self
,name,age,gender):self
.name = nameself
.age = ageself
.gender = gender# 自定义一个 read 函数输出命令
def
read
(self
):print
('这位名叫'
+ self
.name + '的同学正在阅读'
)# 自定义一个 write 函数输出命令
def
write
(self
):print
('这位名叫'
+ self
.name + '的同学正在写字'
)-
类的实例化
接下来我将调用这个 Student 类,生成几个学生对象:
# 使用 class 关键词创建类
student1 =Student
('小明'
,18
,'男'
)student2 =Student
('小红'
,20
,'女'
)student3 =Student
('小亮'
,22
,'男'
)这样就通过调用 Student 类创建了三个学生对象,可以看出,有了类这个模版,可以随意创建任意多的对象,只需要按照类里 __init__ 函数定义的变量,传入对应的参数就完成了。
定义好对象后,我们可以查看对象的属性值也可以调用这个类所具备的函数,具体见下面的教程。
-
访问属性
在 Python 中,可以用英文的句号 . 来访问对象的属性,我们通过以下的代码来访问 student1 对象的内部属性:
student_name = student1.namestudent_age = student1.agestudent_gender = student1.genderprint
(student_name)print
(student_age)print
(student_gender)运行代码,结果如下:
小明
18
男当然,可以随意修改属性的值,直接使用等号进行赋值即可:
student1.name ='小刘'
上面的代码轻松修改了 student1 对象的内部属性,在后面我会介绍其他修改属性的方法。
-
调用方法
在上面类的定义中,我们创建了 Student 类,里面通过 def 关键词定义了 read 和 write 两个函数,一旦我们使用这个类创建了对象,那么对象默认都会具备这些功能,来看看使用方式,这次我使用 student2 作为案例。
调用类中的方法可以使用 . 加函数名称加括号的方式来使用。注意 千万不要忘记加括号 ,不然就是访问属性。
# 先定义 student2 对象
student2 =Student
('小红'
,20
,'女'
)# 调用方法
student2.read
()student2.write
()运行上面代码,结果如下:
这位名叫小红的同学正在阅读
这位名叫小红的同学正在写字调用类中的方法和调用类中的属性方法有一点相似,只是调用方法时后面需要接一个括号,括号内和函数一样传入对应的参数,在上面的案例中由于我们设计类的方法时并没有传入参数,所以调用的时候括号里是空白。
经典案例
下面我将通过一个经典案例来帮助大家更好地掌握类以及对象的使用。
定义一个汽车的类,存储汽车的相关信息,返回一个汇总结果。
# 使用 class 关键词创建类
class
Car
():# 使用 init 函数初始化制造商、型号、生产年份、里程,并设定默认里程是0
def
__init__
(self
,make,model,year):self
.make = makeself
.model = modelself
.year = yearself
.mile_age = 0
# 描述汽车信息的函数输出命令
def
describe
(self
):print
('汽车信息: '
+ self
.make + '-'
+ self
.model + '-'
+ self
.year)# 描述汽车里程的函数输出命令
def
read_mile_age
(self
):print
('这辆汽车的里程数是: '
+ str
(self
.mile_age))# 调用创建好的类并创建一辆汽车对象
Car
('奥迪'
,'A6'
,'2020'
)# 调用该汽车对象的函数
describe
()read_mile_age
()运行上面代码,结果如下:
汽车信息: 宝马-A6-2020
这辆汽车的里程数是: 0
在原代码的基础上我们新增一个修改属性值的函数:
在上面的教程中我们介绍到可以通过等号赋值的方式修改内部的属性值,这次我们使用函数在内部直接进行修改。
class
Car
():# 使用 init 函数初始化制造商、型号、生产年份、里程,并设定默认里程是0
def
__init__
(self
,make,model,year):self
.make = makeself
.model = modelself
.year = yearself
.mile_age = 0
# 直接修改公里数属性的函数
def
update_mile_age
(self
,new_mile_age):# 调用创建好的类并创建一辆汽车对象
Car
('宝马'
,'3系'
,'2022'
)# 调用该汽车查看公里数的函数
read_mile_age
()# 调用该汽车修改公里数的函数
update_mile_age
(100
)# 再次调用该汽车查看公里数的函数
read_mile_age
()运行代码,结果如下:
这辆汽车的里程数是: 0
这辆汽车的里程数是: 100
可以看出,在使用修改属性的函数之前,汽车的公里数是 0 ,修改之后变成了 100 。
由于汽车的公里数只能增加不能减少,于是我调整一下刚才创建的这个函数来防止有人恶意调整里程数,这次我将默认的里程数设定为 100:
# 使用 class 关键词创建类
class
Car
():# 使用 init 函数初始化制造商、型号、生产年份、里程,并设定默认里程是0
def
__init__
(self
,make,model,year):self
.make = makeself
.model = modelself
.year = yearself
.mile_age = 100
# 描述汽车里程的函数输出命令
def
read_mile_age
(self
):print
('这辆汽车的里程数是: '
+ str
(self
.mile_age))# 修改公里数属性
def
update_mile_age
(self
,new_mile_age):if
new_mile_age <= self.mile_age:print
('您不能将里程数调小,请重新修改'
)else
:# 调用创建好的类并创建一辆汽车对象
Car
('宝马'
,'3系'
,'2022'
)# 调用该汽车查看公里数的函数
read_mile_age
()# 将公里数修改变小
update_mile_age
(20
)# 将公里数修改变大
update_mile_age
(200
)# 再次调用该汽车查看公里数的函数
read_mile_age
()运行代码,结果如下:
这辆汽车的里程数是: 100
您不能将里程数调小,请重新修改
这辆汽车的里程数是: 200
可以看出,这次我们将公里数变小后,再次运行程序会抛出禁止修改的信息,此时我们在代码中将用户输入的公里数与 self.mile_age 也就是对象此时的内部属性进行比较,判断大小关系,来判断是修改还是抛出异常提醒。
接下来我们再来新增一个函数,这个函数是每次的新增的公里量,并且如果输入负数,程序会提醒公里数不能减少:
class
Car
():# 使用 init 函数初始化制造商、型号、生产年份、里程,并设定默认里程是0
def
__init__
(self
,make,model,year):self
.make = makeself
.model = modelself
.year = yearself
.mile_age = 100
# 描述汽车里程的函数输出命令
def
read_mile_age
(self
):print
('这辆汽车的里程数是: '
+ str
(self
.mile_age))# 修改公里数属性函数
def
update_mile_age
(self
,new_mile_age):if
new_mile_age <= self.mile_age:print
('您不能将里程数调小,请重新修改'
)else
:# 每次新增公里数的增量函数
def
increase_mile_age
(self
,miles):if
miles < 0
:print
('您不能将里程数调小,请重新修改'
)else
:# 调用创建好的类并创建一辆汽车对象
Car
('奔驰'
,'C级'
,'2023'
)# 调用该汽车查看公里数的函数
read_mile_age
()# 多运行几次增加该车公里数的函数
increase_mile_age
(20
)increase_mile_age
(20
)increase_mile_age
(20
)# 再次调用该汽车查看公里数的函数
read_mile_age()
运行上面代码,结果如下:
这辆汽车的里程数是: 100
这辆汽车的里程数是: 160
可以看出,在新增公里数前的公里数是 100,我运行了三次增量函数,每一次新增 20,最后的结果就是 160 公里。
例题
【例题1】开发一个类似于电商的平台,增加一个购物车功能,可以不断新增商品,并且可以在结算时进行数量统计以及计算商品总价钱。
在这个例题中,我会创建两个类,第一个类代表 “商品”,适用于全部的商品品类,另一个类代表 “购物车”,购物车的目的是统计传入的所有商品,并进行计算总数和总价。
# 定义一个描述商品信息的类
class
Product
():# 使用 init 函数初始商品的价钱、购买数量
def
__init__
(self
,name,price,count):self
.name = nameself
.price = priceself
.count = count# 计算该商品总价
def
product_total_price
(self
):return
self
.price * self
.count# 定义一个描述购物车信息的类
class
ShopCar
():# 使用 init 函数初始商品信息,用一个列表存储
def
__init__
(self
):self
.product_list = []# 向购物车中新增商品的函数,存入的商品是 Product 对象
def
add_product
(self
,product):self
.product_list.append(product)# 在购物车中删除商品
def
remove_product
(self
,product):self
.product_list.remove(product)# 计算购物车中全部商品总金额
def
shop_car_total_price
(self
):0
# 循环调用购物车中每个商品 Product 对象
for
i in
self
.product_list:# 在这里调用列表中每个 Product 对象的计算总金额函数
return
'您的购物车中商品的总金额是'
+str
(total_price)+'元。'
# 计算购物车中全部商品总数量
def
shop_car_total_count
(self
):0
# 循环调用购物车中每个商品 Product 对象
for
i in
self
.product_list:# 在这里调用列表中每个 Product 对象的 count 属性
return
'您的购物车中一共有'
+str
(total_count)+'件商品。'
# 统计购物车全部商品的名称
def
shop_car_total_name
(self
):# 循环调用购物车中每个商品 Product 对象
for
i in
self
.product_list:# 在这里调用列表中每个 Product 对象的 name 属性
return
'购物车中的全部商品有:'
+ '、'
.join(names) + '。'
上面的代码完成了商品的类和购物车的类的定义,其中在购物车的类中需要传入商品对象,下面我们来调用这两个类:
# 调用 Product 类创建几个商品
Product
('铅笔'
,5
,10
)Product
('鸡蛋'
,1
,20
)Product
('椅子'
,50
,5
)Product
('手机'
,1000
,1
)# 创建 ShopCar 类并使用该类里 add_product 函数并将上面创建的 Product 对象传进去
ShopCar
()add_product
(product1)add_product
(product2)add_product
(product3)add_product
(product4)# 计算购物车中全部商品总数量
shop_car_total_count
()# 计算购物车中全部商品总金额
shop_car_total_price
()# 输出购物车中全部商品名称
shop_car_total_name
()# 输出结果
print
(my_count)print
(my_total_price)print
(my_product_names)运行上面代码,结果如下:
您的购物车中一共有36件商品。
您的购物车中商品的总金额是1320元。
购物车中的全部商品有:铅笔、鸡蛋、椅子、手机。
当我在购物车中再加几件物品:
add_product
(Product
('拖鞋'
,20
,2
))add_product
(Product
('蚊香'
,10
,2
))再次运行代码输出结果:
shop_car_total_count
()shop_car_total_price
()shop_car_total_name
()print
(my_count)print
(my_total_price)print
(my_product_names)结果如下:
您的购物车中一共有40件商品。
您的购物车中商品的总金额是1380元。
购物车中的全部商品有:铅笔、鸡蛋、椅子、手机、拖鞋、蚊香。
可以看出,my_shop_car 购物车随着我们新增商品,其结果也在不断地变化,是一个动态的过程。
关注公众号【牧旗教程】,回复“更多例题”,获取更多题型进行训练~
您的打赏将帮助维护网站服务器的正常运营,并为作者的后续更新提供更多的动力。
Copyright © 2013-2023 Muqi Course. All Rights Reserved. 牧旗教程 版权所有 京ICP备2023029281号