面向对象
布尔微信:Matongxue_6
# 面向对象基础
# 第一节 类和封装
# 目标
- 理解面向对象
- 类和对象
- 添加和获取对象属性
# 一.理解面向对象
在讲面向对象之前,总结一下面向过程
# 1.1.面向过程:根据业务逻辑从上到下写代码
面向过程编程最易被初学者接受,
往往用一长段代码来实现指定功能,
开发过程的思路是:
将数据与函数按照执行的逻辑顺序组织在一起,
数据与函数分开考虑。
while True:
if cpu利用率 > 90 %:
组装当前系统日志
发送报警邮件
保存当前的交互数据
关闭系统
if 硬盘使用 > 95 %:
组装当前系统日志
发送报警邮件
保存当前的交互数据
关闭系统
if 内存使用 > 90 %:
组装当前系统日志
发送报警邮件
保存当前的交互数据
关闭系统
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
随着时间的推移,开始使用了函数式编程,增强代码的重用性和可读性,就变成了这样.
def 资源告警处理(告警原因):
组装当前系统日志
发送报警邮件
保存当前的交互数据
关闭系统
while True:
if cpu利用率 > 90 %:
资源告警处理(cpu告警)
if 硬盘使用 > 95 %:
资源告警处理(硬盘告警)
if 内存使用 > 90 %:
资源告警处理(内存告警)
2
3
4
5
6
7
8
9
10
11
12
13
面向对象 编程则是另一种解决问题的思路
*多说一句,在python中“面向过程(函数式)” 和“面向对象”编程一样重要
class MonitoringSystem(object):#类
#系统监控模块
def 资源告警处理(告警原因):
组装当前系统日志
发送报警邮件
保存当前的交互数据
关闭系统
def 开始监控():
while True:
if cpu利用率 > 90 %:
资源告警处理(cpu告警)
if 硬盘使用 > 95 %:
资源告警处理(硬盘告警)
if 内存使用 > 90 %:
资源告警处理(内存告警)
系统1 = MonitoringSystem()
系统1.开始监控()
系统2 = MonitoringSystem()
系统2.开始监控()
系统3 = MonitoringSystem()
系统3.开始监控()
.......
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
面向对象:对整个代码逻辑(包含数据、函数、逻辑)进行包装(专业术语:封装),最大程度提升代码复用,减少编码量
为什么我们要在这个节点学习面向对象?
因为绝大多数的python库都使用了“面向对象”的方式来编写,故而不懂”对象“。就没法真正学会python
# 小结
1)面向过程-----怎么做?
1.把完成某一个需求的所有步骤从头到尾逐步实现
2.根据业务需求,将某些功能独立的代码封装成一个又一个函数
3.最后完成的代码,就是顺序的调用不同的函数
特点
1.注重步骤与过程,不注重职责分工
2.如果需求复杂,代码会变得很复杂
3.开发复杂项目,没有固定的套路,开发难度很大
2)面向对象--------谁来做?
相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
1.在完成某一个需求前,首先确定职责-------要做的事情(方法)
2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3.最后完成的代码,就是顺序地让不同的对象调用不同的方法
特点
1.注重对象这一抽象概念
2.更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供固定套路
3.需要在面向过程基础上,再学习一些面向对象的语法
# 1.2.进一步理解面向对象
好吧,我要学习面向对象了。但还是有点懵懵的呀
# 1.2.1 阅读理解:买电脑
第一种方式(面向过程)
1)在网上查找资料
2)根据自己预算和需求定电脑的型号ThinkPad P70顶配windows10系统1W3
3)去市场找到联想店各种店无法甄别真假随便找了一家
4)找到业务员,业务员推荐了另外一款配置更高价格便宜,也是windows10系统的1W
5)砍价30分钟付款9088
6)成交
7)回去之后发现各种问题-开始走上维权之路
第二种方式(面向对象)
1)找一个靠谱的电脑高手
2)给钱交易
# 面向对象 和 面向过程 都是解决问题的一种思路,目的都是“买电脑”
面向过程:强调的是步骤、过程、每一步都是自己亲自去实现。类比到编程,每一行代码都是为了一个目的而写的。缺乏复用性
面向对象:强调的是电脑高手,电脑高手是处理这件事的主角,对我们而言,我们并不必亲自实现整个步骤只需要调用电脑高手就可以解决问题。
回到编程里,“电脑高手”可能是别人写好的“对象”。我们并不深究 高手 是如何实现功能的,知识确认“对象”能帮我们达到目的。这种解决问题的思路就是面向对象。
所以说,学习面向对象。用面向对象的思维解决问题的重点!
当遇到一个需求的时候,先对问题进行抽象。百度是否有可以借鉴的库或者类
# 练习题1
需求:
- 小明今年18岁,身高1.75,每天早上跑完步,会去吃东西
- 小美今年17岁,身高1.65,小美不跑步,小美喜欢吃东西
练习2
需求:
- 一只黄颜色的狗狗叫大黄
- 看见生人汪汪叫
- 看见家人摇尾巴
# 二.类和对象(封装)
# 2.1 理解类和对象
# 2.1.1类
类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。
- 特性即是属性
- 行为即使方法
类就相当于制造飞机的图纸,就是一个模板,是负责创建对象的
# 2.1.2对象
- 对象是由类创造出来的一个具体存在的,可以直接使用的
- 由哪一个类创建出来的对象,就拥有在哪一个类中定义的:
- 属性
- 方法
- 对象 就相当于用图纸制造的飞机
在程序开发中,应该先有类,再有对象
# 2.2类和对象的关系
- 类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象
- 类只有一个,而对象可以有很多个
- 不同的对象之间属性可能会各不相同
# 2.3 类的设计
在使用面向对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类
在程序开发中,要设计一个类,通常要满足一下三个要素
1.类的名称: 描述的这类事务
2.类的属性: 一组数据
3.类的方法:这个类允许的行为
# 2.4面向对象实现方法
class 类名():
代码
2
注意:类名要满足标识符命名规则,同时遵循大驼峰命名习惯
- 体验
class Plane():
def fly(self):
print('我会飞')
2
3
4
5
# 2.4.1创建对象
对象又名实例
- 语法
对象名 = 类名()
- 体验
#创建对象
plane1 = Plane()
print(plane1)
plane1.fly()
2
3
4
注意:创建对象的过程叫实例化
# 2.4.2 self
self 指的是调用该函数的对象
# 1.定义一个类
class plane():
def fly(self):
print('我会飞')
print(self)
#2 实例化两个对象
redplane = plane()
print(redplane)
blueplane = plane()
print(blueplane)
# 3.调用实例方法
redplane.fly()
blueplane.fly()
2
3
4
5
6
7
8
9
10
11
12
13
注意:打印对象和self得到的结果是一致的,都是当前内存中存储的地址
# 三.添加和获取对象属性
属性即是特征,比如:飞机的长,宽,重量:
对象属性既可以在类外面添加和获取,也能在类里面添加和获取
# 3.1类外面添加对象属性
- 语法
对象名.属性名 = 值
- 体验
redplane.lenth = 400
redplane.weight = 500
2
# 3.2 类外面获取对象属性
- 语法
对象名.属性名
体验
print(redplane.weight) print(redplane.lenth)
1
2
# 3.3类里面获取对象属性
self.属性名
# 四.类属性和实例属性
# 4.1类属性
# 4.1.1设置和访问类属性
- 类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有
- 类属性可以使用类对象或实例对象访问
class Dog(object):
tooth = 10
wangcai =Dog()
xiaohei = Dog()
print(Dog.tooth) # 10
print(wangcai.tooth) #10
print(xiaohei.tooth) # 10
2
3
4
5
6
7
8
9
10
类属性的优点
- 类的实例,记录的某项数据 始终保持一致时,则定义类属性
- 实例属性 要求每个对象为其单独开辟一份内存空间 来记录数据,而类属性为全类所共有,仅占用一份内存,更加节省内存空间。
# 4.1.2修改类属性
类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的时创建了一个实例属性
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
# 修改类属性
Dog.tooth = 20
print(Dog.tooth) # 20
print(wangcai.tooth) #20
print(xiaohei.tooth) # 20
print('*' * 10)
wangcai.tooth = 30
print(wangcai.tooth) #给实例对象增加一个实例属性 30
print(Dog.tooth) # 20
print(xiaohei.tooth) # 20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 4.2 实例属性
class Dog(object):
def __init__(self):
self.age= 5
def info_print(self):
print(self.age)
wangcai = Dog()
print(wangcai.age)
# print(Dog.age) #报错,实例属性不能通过类去访问
wangcai.info_print() # 5
2
3
4
5
6
7
8
9
10
# 五.类方法和静态方法
# 5.1类方法
# 5.1.1 类方法特点
- 第一个形参时类对象的方法
- 需要用装饰器
@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数。
# 5.1.2 类方法使用场景
- 当方法中 需要使用类对象(如访问私有属性等)时,定义类方法
- 类方法一般和类属性配合使用
class Dog(object):
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth
wangcai = Dog()
result = wangcai.get_tooth() #实例对象访问类方法
print(result) # 10
print(Dog.get_tooth()) # 10 类对象访问类方法
2
3
4
5
6
7
8
9
10
# 5.2 静态方法
# 5.2.1 静态方法特点
- 需要通过装饰器
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self
或者cls
) - 静态方法 也能通过实例对象和类对象去访问
# 5.2.2静态方法使用场景
- 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性,类方法,创建实例对象等)时,定义 静态方法
- 取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
class Dog(object):
@staticmethod
def info_print():
print('这是一个狗类,用于创建狗的实例......')
wangcai = Dog()
#静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()
2
3
4
5
6
7
8
9
# 第二节 面向对象-继承
# 目标
- 继承的概念
- 继承实例
- 子类重写父类的同名属性和方法
- 子类调用父类的同名属性和方法
# 一.继承的概念
生活中的继承,一般指的是子女继承父辈的财产。
Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性的方法,具体如下:
#父类A
class A(object):
def __init__(self):
self.num = 1
def info_print(self) :
print(self.num)
#子类B
class B(A):
pass
son = B()
son.info_print()
2
3
4
5
6
7
8
9
10
11
12
在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。
# 二.继承实例
故事主线:一个做麻辣香锅的老师傅,在麻辣香锅界摸爬滚打多年,研发了一套精湛的麻辣香锅的技术。师傅老师,要把这套技术传授给他的唯一的最得意的徒弟。
分析:徒弟是不是要继承师父的所有技术?
# 1师傅类
class Teacher(object):
def __init__(self):
self.kongfu = '独门麻辣香锅'
def make_food():
print(f'用{self.kongfu}做出最美味的麻辣香锅')
#2徒弟类
class Student(Teacher):
pass
# 3.创建对象徒弟zhouyuan
zhouyuan = Student()
# 对象调用实例方法
zhouyuan.make_food()
# 对象访问实例属性
print(zhouyuan.kongfu)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 三.子类重写父类同名方法
故事:
zhouyuan
掌握了师父和培训的技术后,自己潜心钻研出自己的独⻔配方的一套全新的麻辣香锅技术。
# 1师傅类
class Teacher(object):
def __init__(self):
self.kongfu = '独门麻辣香锅'
def make_food(self):
print(f'用{self.kongfu}做出最美味的麻辣香锅')
class Testfan(object):
def __init__(self):
self.kongfu = 'testfan麻辣香锅'
def make_food(self):
print(f'用{self.kongfu}做出最独特的麻辣香锅')
#2徒弟类
class Student(Testfan,Teacher):
def __init__(self):
self.kongfu = '最炫的麻辣香锅'
def make_food(self):
print(f'申请专利的{self.kongfu}')
zhouyuan=Student()
print(zhouyuan.kongfu)
zhouyuan.make_food()
print(Student.__mro__)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。
# 四.子类调用父类的同名方法和属性
故事:很多顾客都希望也能吃到独门和
testfan
的技术的麻辣香锅。
# 1师傅类
class Teacher(object):
def __init__(self):
self.kongfu = '独门麻辣香锅'
def make_food(self):
print(f'用{self.kongfu}做出最美味的麻辣香锅')
class Testfan(object):
def __init__(self):
self.kongfu = 'testfan麻辣香锅'
def make_food(self):
print(f'用{self.kongfu}做出最独特的麻辣香锅')
#2徒弟类
class Student(Testfan,Teacher):
def __init__(self):
self.kongfu = '最炫的麻辣香锅'
def make_food(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(f'申请专利的{self.kongfu}')
# 调用父类方法,但是为了保证调用的也是父类的属性,必须在调用方法前调用父类的初始化
def make_teacher_food(self):
Teacher.__init__(self)
Teacher.make_food(self)
def make_testfan_food(self):
Testfan.__init__(self):
Testfan.make_food(self)
zhouyuan = Student()
zhouyuan.make_food()
zhouyuan.make_teacher_food()
zhouyuan.make_testfan()
zhouyuan.make_food()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 第三节 面向对象-多态
# 目标
- 多态
# 一.多态
# 1.1了解多态
多态指的指的时一类事物有多种形态,(一个抽象的类有多个子类,因为多态的概念建立在继承的基础上)
- 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同方法,可以产生不同的执行结果。
- 好处:调用灵活,有了多态,更容易编出通用的代码,做出通用的编程,以适应需求的不断变化。
- 实现步骤:
- 定义父类,并提供公共方法
- 定义子类,并重写父类方法
- 传递子类对象给调用者,可以看到不同子类执行效果不同
# 1.2 体验多态
鸭子类型是python中多态的一种实现方式。
鸭子类型强调关注事物的行为而不是事物本身和事物的表现,
如果某些类都实现了同名方法,
那这些类也就实践了“多态”,即赋予一个“方法(名称)”多种多样的功能
# 多态的第一种写法,没有关联的类实现了“同名方法”
class Duck(): # 鸭子类
def Quack(self):
print("呱呱")
class Swan(): # 天鹅类
def Quack(self):
print("鹅鹅")
class Plane(): # 飞机类
def Quack(self):
print("隆隆隆")
def Quack(obj): # 实现飞的功能函数
obj.Quack()
duck = Duck()
Quack(duck)
swan = Swan()
Quack(swan)
plane = Plane()
Quack(plane)
# 多态的第二种写法。通过继承关系
class Dog():
text = '喜欢溜达'
def play(self):
print(self.text)
class LilyDog(Dog):
text = '喜欢在商城溜达'
#通过继承,得到了Dog类的 pyay()方法
class TomDog(Dog):
text = '喜欢在公园溜达'
# 通过继承,得到了Dog类的 pyay()方法
class Pet():
def play_with_dog(self,dog):
dog.play()
lily=LilyDog()
var=Pet()
var.play_with_dog(lily)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 写在最后
对于面向对象编程,人们开始意识到,严格的面向对象方法会带来很多问题。这些问题往往会使代码更复杂、更难以理解且更难以测试。
“鸭嘴兽”效应
现实是:我们要做的事并不总是能被整洁地划分为具有明确属性定义的类(class)。
例如:假设你创建了一个代表动物王国的类层次结构(类)。
现在,有爬行动物——冷血,有鳞片,卵生等等。
还有哺乳动物——温血,有绒毛,胎生。
以及鸟类,两栖动物,无脊椎动物等等
然后鸭嘴兽出现了。
它似乎不适合你的任何类别。
你该怎么做呢?
你是创建一个全新的类别呢:
例如:鸭嘴兽类-鸭嘴兽,有且只有它一个成员(实际上生物学家确实是这么干的)
还是重新考虑整个分类方案?
哺乳动物——温血,有绒毛,胎生/鸭嘴兽(唯二的卵生哺乳动物)
这两种方法在工作量和程序复杂性方面都会产生巨大的成本。
所以在真正编码的时候,python认为“面向过程(函数)” 和“面向对象”一样重要。他们都有合适的运用场景
[TOC]