有点抽象,其实是一种编程思想。
说到面向对象,不得不提面向过程;
面向过程与面向对象:
面向过程:
根据业务逻辑从上到下的写代码实现功能,聚合性较高。
面向对象:
将数据与函数绑定在一起,进行封装,减少重复代码的重写过程,耦合度较高,更加灵活便捷
举个例子:
把大象放进冰箱:
面向过程是这样的:
- 打开冰箱门
- 把大象塞进去
- 关上冰箱门
面向过程编程就是分析出解决问题所需要步骤,然后分别实现每一步,再一步步执行即可。
面向对象是这样的:
这里要先搞清楚,面向对象是什么?搞清楚啥是对象?
万物皆对象:比如,我们把冰箱视为一个对象,那么它是由什么组成的呢?又可以用来干什么?
因此:对象 = 属性 + 行为
下面,我们用面向对象,来实现把大象放进冰箱:
- 调用:冰箱 -> 打开门(行为)
- 调用:冰箱 -> 装东西(行为)
- 调用:冰箱 -> 关闭门(行为)
看起来和面向过程没啥区别,但我们的思想发生了重大的转变,我们把冰箱当作了一个独立的对象,我们是通过和冰箱这个对象交互完成了整个过程。
重点在于:如果我们有时候需要对某个对象,进行增删改,单独对其进行操作则使用面向对象更方便;而面向过程改动前一个就会影响后一个,发生一连串的连锁反应。
但并不是说面向对象有多好,面向过程有多么不好,是想说:我们可以根据具体的场景,来决定采用哪个编程方式或思想。
类:
用来描述具有相同属性和方法的对象的集合,
比如:“人”是一个类,“植物”是一个类...
对象:
某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的,
比如:“胡歌”是一个对象
在开发中,是先有类,再有对象。
类与对象的关系:
- 类是对象的抽象
- 对象是类的实例
我们可以进行对象归类: 举例:分析班级同学共有的特征,进行归类:
然后,还可以对学生公有的特征进行归类,从而建立一个学生类:
练习:
下面哪些是类?哪些是对象?
- 汽车
- 奔驰、宝马、五菱、红旗、几何...
- 水果
- 香蕉、苹果、橘子、奇异果、芒果...
类的构成:
类由3个部分构成:
- 类的名称:类名
- 类的属性:一组数据
- 类的方法:允许对类进行操作的方法
注意:类名通常采用驼峰式命名方式,尽量让字面意思体现出类的作用。
类的定义:
Python使用class关键字来定义类,其基本结构如下:
class 类名:
pass
如何创建对象:
Python中,可以根据已经定义的类去创建出一个个对象 创建对象的格式为:
对象名 = 类名()
练习:
- 创建类:学生类
- 创建对象:张三
- 在类中定义方法输出:张三学习Python
class Students: # 创建一个类
# 定义一个类的方法/函数
def study(self):
print('我正在学习面向对象,你呢?')
# 创建对象(实例),这个过程即是实例化对象
a = Students()
# 执行类中的方法
a.study()
self 参数:
在类当中定义方法时,会发现系统帮我们自动创建了 self 参数,并且在调用对象的该方法时,也无需传入 self 参数。那这个 self 是什么? 接下来一起先看个例子:
举例:
- 定义类为:demo类
- 创建对象:崔东山
- 在类中定义方法:打印李四信息
class demo:
def func(self):
print(f'你好哇,我是{ls.name},我今年{ls.age}岁,很高兴认识你。')
ls = demo()
ls.name = '崔东山'
ls.age = '80'
ls.func()
通过这个例子,可以看出,对象将自身的信息在类的外部定义并赋值,封装到了类的内部。 即:self是:
- self本身是形参
- self就是当前对象本身
当我再想创建一个对象时并打印对应信息时,发现这样并不是很灵活,因此可以优化如下:
class demo:
def func(self):
print(f'你好哇,我是{self.name},我今年{self.age}岁了,很高兴认识你。')
ls = demo()
ls.name = '东山'
ls.age = '80'
ls.func()
zs = demo()
zs.name = '平安'
zs.age = '40'
zs.func()
但是这样仍然有缺陷,我们会发现,用户信息暴露在类的外部。
魔法方法( Magic methods ):
在Python的类中,以两个下划线开头、两个下划线结尾的方法,如常见的 : init、str、del等,就被称为「魔法方法」。
因为这些方法都是到达某个条件自动触发 无需调用,所以,称之为 魔法方法。
init():初始化对象_不带参数时:
在创建⼀个对象时默认被调⽤,不需要⼿动调⽤
init(self) 中的self参数,不需要开发者传递,python解释器会⾃动把当前的对象引⽤传递过去。
class my_apple:
# 初始化
def __init__(self):
self.width = 10
self.high = 20
def main(self):
print(self.width)
print(self.high)
iPad = my_apple()
iPad.main()
init(),带参数时:
⼀个类可以创建多个对象, 对不同的对象设置不同的初始化属性:传参即可。
class MyMobilePhone:
def __init__(self, size, color):
self.size = size
self.color = color
def my_huawei(self):
print(f'我的华为手机尺寸是{self.size},其机身颜色为{self.color}。')
def my_apple(self):
print(f'我的苹果手机尺寸是{self.size},机身的颜色是{self.color}。')
# 对不同的对象,设置不同的初始化属性
mobile_1 = MyMobilePhone(6.5, '白色')
mobile_1.my_huawei()
mobile_2 = MyMobilePhone(5.5, '紫色')
mobile_2.my_apple()
str():
当使⽤ print 输出对象的时候,默认打印对象的内存地址。类定义了 str() ⽅法后,会打印在这个⽅法中 return 的数据。 解释类的属性或作用.
class Demo_1:
def __init__(self, width, height):
self.width = width
self.height = height
def __str__(self):
return f'这部手机的宽为:{self.width},高为:{self.height}'
a = Demo_1(10, 20)
print(a)
del():
在对象销毁时被调用,当对象不再被使用时,del()方法则运行。
class Demo_2:
def __init__(self, color, size):
self.color = color
self.size = size
def __del__(self):
print('对象已被删除...')
b = Demo_2('天蓝色', 30)
class Demo_3:
# 当由该类创建的实例对象,被删除或者在内存中被释放,将会自动触发并执行。
def __del__(self):
print('被释放了..') # 程序执行完,最后调用
c = Demo_3()
print('-----')
类的属性与方法:
类的私有属性:
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。
class Demo:
__num = 0 # 私有属性,以2个下划线开头
result = 0
def Count(self):
self.__num += 3
self.result += 1
print(f'打印私有变量的值:{self.__num}')
print(f'打印公开属性的值:{self.result}')
def GetNum(self):
return self.__num
number = Demo()
number.Count()
print('在外面,直接打印公开的属性值:', number.result)
# print(number.__num) # 报错,实例(对象)不能访问私有变量
num = number.GetNum()
print(f'当私有属性,被实例调用方法后:返回值为{num}') # 3
类的私有方法:
class Demo_2:
def func_1(self):
print('这是公开的方法,随便打印个内容--111')
# 类的私有方法
def __func_2(self):
print('这是私有方法,随便打印个内容--222')
def func_3(self):
return self.__func_2()
f = Demo_2()
f.func_1()
# f.__func_2() # 报错:AttributeError: 'Demo_2' object has no attribute '__func_2',对象没有属性
f.func_3()
# 不建议这样使用:对象._类名__私有属性
print(f._Demo_2__func_2) # <bound method Demo_2.__func_2 of <__main__.Demo_2 object at 0x100750b50>>
实例属性:
class Province:
# 初始化
def __init__(self, country, province):
self.country = country
self.province = province
def PrintInfo(self):
# 通过self去访问,当对象有很多个时,会方便很对
print(f'您当前停留在{self.country},所在省份为{self.province}')
# 通过每个对象去访问,当对象有很多个时,这样比较麻烦
print(HuNan.country, HuNan.province)
HuNan = Province('中国', '湖南')
HuNan.PrintInfo()
zg = Province('中国', '北京')
zg.PrintInfo()
实例方法:
class Demo:
def __init__(self):
self.name = 'Maria'
# 实例方法
def func(self):
print(self.name)
a = Demo()
a.func()
下面来个综合应用的练习:
烤地瓜:
题目分析:
涉及一个事物,地瓜,因此需要涉及到一个类:地瓜类
地瓜类的属性:
- 被烤的时间
- 被烤后的状态
地瓜的实例方法:
- 可以被加热烤熟
- 可以根据口味添加对应的调料
打印对象的信息
需求:
1、被烤的时间和地⽠对应的状态:
- 0 - 5分钟 : ⽣的
- 5 - 10分钟 : 半⽣不熟
- 10-12分钟 : 烤熟了
- 超过12分钟: 烤糊了
2、添加调料:
代码实现:
class RoastedSweetPotato:
# 初始化
def __init__(self):
self.cookTime = 0
self.cookState = '生的'
self.cookTaste = []
# 烤的时间
def cook(self, time):
# 初始值 加上 被烤的时间
self.cookTime += time
if 0 <= self.cookTime < 5:
self.cookState = '当前还是生的'
if 5 <= self.cookTime < 10:
self.cookState = '快烤熟了'
if 10 <= self.cookTime < 12:
self.cookState = '已经烤熟啦'
if self.cookTime >= 12:
self.cookState = '哎呀,糟糕,烤糊了'
# 添加调味料
def addSeasoning(self, *args):
self.cookTaste.append(args)
# 显示地瓜状态
def __str__(self):
return f'这个地瓜已经烤了{self.cookTime}分钟,当前状态为{self.cookState}'
if __name__ == '__main__':
# 创建对象
eat = RoastedSweetPotato()
# 调用烤的方法,传入烤的时间
eat.cook(11)
# 调用添加的调料,传入添加的调料
eat.addSeasoning('辣椒面', '椒盐')
# 打印自定义内容
print(eat)