Python——面向对象
面向对象
一. 理解面向对象
面向对象是一种抽象化的编程思想,很多编程语言中都有的一种思想。
面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事。
在面向对象编程过程中,有两个重要组成部分: 类 和 对象 。
类: 比如是制造洗衣机时要用到的图纸
对象 : 比如是就是用图纸造出来的洗衣机
类是对一系列具有相同 特征 和 行为 的事物的统称
类和对象的关系:用类去创建一个对象。 那么对象就有自己的特征 和 行为
- 特征即是属性
比如 : 年龄 相貌, 地域 ,身高 体重 - 行为即是方法
比如 : 飞 ,洗 打 烤 ,跑 ,看
类和对象的关系 :对象是由类创造出来的!
注意:先有类,再有对象。
二. 面向对象实现方法
2.1 定义类
Python2中类分为:经典类 和 新式类
- 新式类
class 类名():
代码
......
# 类的写法
class Washer():
pass
注意:类名要满足标识符命名规则,注意,首字母大写!,同时遵循 大驼峰命名习惯 。
- 经典类
不由任意内置类型派生出的类,称之为经典类,现在几乎很少用,但得知道
class 类名:
代码
......
class Washer:
pass
2.2 创建对象
对象又名实例。
- 语法
对象名 = 类名()
# 创建对象
class Washer():
pass
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)
注意:创建对象的过程也叫实例化对象。
2.3 对象的属性 __init__()
__init__()
方法的作用:初始化对象。
通俗一点讲 : __init()__
里面就是对象属性的"聚集地"
对象属性既可以在类外面添加和获取,也能在类里面添加和获取。
class Washer(): # 定义初始化功能的函数
def __init__(self): # 添加实例属性
self.width = 500 # 宽度是 500
self.height = 800 # 高度 是 800
haier1 = Washer()
print(haier1.width)
class Washer(): # 定义初始化功能的函数
def __init__(self, color): # 添加实例属性
self.width = 500 # 宽度是 500
self.height = 800 # 高度 是 800
self.yanse = color
haier1 = Washer('yellow')
print(haier1.yanse)
注意:
__init__()
方法,在创建一个对象时默认被调用,不需要手动调用__init__(self)
中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。
2.4 self参数
self指的是调用该函数的对象。
class Washer(): # 定义初始化功能的函数
def __init__(self): # 添加实例属性
self.width = 500 # 宽度是 500
self.height = 800 # 高度 是 800
# print(self)
haier1 = Washer()
print(haier1.width) # 500
# 此时会有两个疑惑 ?
# 1 : __init__ 是一个函数 ,但是为什么没看到调用 ?
# 2 : 函数里面有参数 self ,为什么没看到传参 ?
# 首先看看 self是什么 ? 此时会发现,self 和 haier1 是一样的 所以 ,self就是那个对象
print(haier1) # <__main__.Washer object at 0x0000000000437490>
haier2 = Washer()
# <__main__.Washer object at 0x0000022005857EF0>
print(haier2)
2.5 实例属性与类属性
Python在广义上的属性有两种:类属性、实例属性
实例属性
一般是在构造函数__init__()中定义的,定义必须使用self前缀,只能通过对象名来访问
class Dog():
def __init__(self):
self.age = 5
def info_print(self):
print(self.age)
wangcai = Dog()
print(wangcai.age) # 5
# print(Dog.age) # 报错:实例属性不能通过类访问
wangcai.info_print() # 5
类属性
- 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
- 类属性可以使用 类对象 或 实例对象 访问。
- 实例属性只能是对象来访问,类对象不可以
- 类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个实例属性。
class Dog():
tooth = 10
wangcai = Dog()
xiaohei = Dog()
print(Dog.tooth) # 10
print(wangcai.tooth) # 10
print(xiaohei.tooth) # 10
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
# 修改类属性
Dog.tooth = 12
print(Dog.tooth) # 12
# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12
类属性的优点
- 记录的某项数据 始终保持一致时,则定义类属性。
- 实例属性 要求 每个对象 为其 单独开辟一份内存空间 来记录数据,而 类属性 为全类所共有 ,仅占用一份内存,更加节省内存空间。
2.6 保护机制
私有成员:为了数据封装和保密而设的属性,一般只能在类的成员方法中使用访问。如果属性名以两个下划线开头’__'则表示是私有属性。
公有成员:可以公开使用,既可以在内部进行访问,也可以在外部程序中使用。
保护成员:只有类对象和子类对象能访问这些成员,如果属性名以一个下划线开头’_'则表示是私有属性。
class A:
def __init__(self,value1=0,value2=0):
self._value1=value1 #定义保护成员
self.__value2=value2 #定义私有成员
def setValue(self,value1,value2):
self.__value1=value1
self.__value2=value2
def show(self):
print(self._value1)
print(self.__value2)
a=A()
a._value1
a.__value2 # 报错
2.7 对象的方法
class Washer(): # 定义初始化功能的函数
def __init__(self): # 添加实例属性
self.width = 500 # 宽度是 500
self.height = 800 # 高度 是 800
# print(self)
def wash(self): # 实例方法
print(f'我是{self}的方法,这个必须用对象(实例)调用我才能运行')
def broke(self):
print('经过很多年以后,被使坏了.')
haier1 = Washer()
print(haier1.width) # 500
haier1.wash() # 调用实例方法
haier1.broke()
三. 魔法方法
3.1 __str__()
当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__
方法,那么就会打印从在这个方法中 return 的数据。
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height
def __str__(self):
return '这是海尔洗衣机的说明书' # 必须得是字符串形式
haier1 = Washer(10, 20)# 这是海尔洗衣机的说明书
print(haier1)
四. 继承机制
继承是为了代码复用和设计复用而设计的,在继承关系中,已有的、设计好的类称为父类或者基类,新设计的类叫做子类或者派生类,派生类可以继承基类的公有成员,但不能继承私有成员。
4.1 单继承
故事主线:一个烤冷面老师傅,在烤冷面界摸爬滚打多年,研发了一套精湛的摊烤冷面的技术。师父要把这套技术传授给他的唯一的最得意的徒弟。
分析:徒弟是不是要继承师父的所有技术?
# 1. 师父类
class Master():
def __init__(self):
self.kongfu = '[古法烤冷面配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作烤冷面')
# 2. 徒弟类
class Prentice(Master):
pass
# 3. 创建对象daqiu
daqiu = Prentice()
# 4. 对象访问实例属性
print(daqiu.kongfu)
# 5. 对象调用实例方法
daqiu.make_cake()
4.2 多继承
同时继承多个父类,如果父类中有相同的方法名,而在子类中使用时没有指定父类名,则会按继承的顺序从左到右顺序进行搜索。
class SchoolA():
def make_cake(self):
print('制作schoolA煎饼果子')
def make_noodles(self):
print('制作schoolA烤冷面')
# 创建学校类
class SchoolB():
def make_cake(self):
print('制作schoolB的煎饼果子')
class Prentice(SchoolB, SchoolA):
pass
daqiu = Prentice()
daqiu.make_cake() #输出SchoolB的make_cake
daqiu.make_noodles()
4.3 重载
即子类重写父类同名方法
class SchoolA(object):
def make_cake(self):
print('制作SchoolA煎饼果子')
class SchoolB(object):
def make_cake(self):
print('制作SchoolB煎饼果子')
# 独创配方
class Prentice(SchoolB, SchoolA):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
print(Prentice.__mro__) # 查看继承顺序
4.4 小难题
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
1 1 1
1 2 1
3 2 3
#Parent.x = 3 父类重新定义了x Parent.x=3
#child1自己有X 故 child1.x = 2
#child2并没有X 执行父类的x child.x = 3
五. 综合应用—烤地瓜
5.1 需求
需求主线:
被烤的时间和对应的地瓜状态:
-
0-3分钟:生的
-
3-5分钟:半生不熟
-
5-8分钟:熟的
-
超过8分钟:烤糊了
添加的调料:
用户可以按自己的意愿添加调料
5.2 步骤分析
需求涉及一个事物: 地瓜,故案例涉及一个类:地瓜类。
(1) 定义类
-
地瓜的属性
- 被烤的时间
- 地瓜的状态
- 添加的调料
-
地瓜的方法
- 被烤
- 用户根据意愿设定每次烤地瓜的时间
- 判断地瓜被烤的总时间是在哪个区间,修改地瓜状态
- 添加调料
- 用户根据意愿设定添加的调料
- 将用户添加的调料存储
- 被烤
-
显示对象信息
(2) 创建对象,调用相关实例方法
5.3 代码实现
(1) 定义类
- 地瓜属性
- 定义地瓜初始化属性,后期根据程序推进更新实例属性
class SweetPotato():
def __init__(self):
# 被烤的时间
self.cook_time = 0
# 地瓜的状态
self.cook_static = '生的'
# 调料列表
self.condiments = []
(2) 定义烤地瓜方法
def cook(self, time):
"""烤地瓜的方法"""
self.cook_time += time
if 0 <= self.cook_time < 3:
self.cook_static = '生的'
elif 3 <= self.cook_time < 5:
self.cook_static = '半生不熟'
elif 5 <= self.cook_time < 8:
self.cook_static = '熟了'
elif self.cook_time >= 8:
self.cook_static = '烤糊了'
(3) 书写str魔法方法,用于输出对象状态
def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}'
(4) 创建对象,测试实例属性和实例方法
digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
print(digua1)
(5) 定义添加调料方法,并调用该实例方法
def add_condiments(self, condiment):
"""添加调料"""
self.condiments.append(condiment)
def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}, 添加的调料有{self.condiments}'
5.4 代码总览
class SweetPotato():
def __init__(self):
# 被烤的时间
self.cook_time = 0
# 地瓜的状态
self.cook_static = '生的'
# 调料列表
self.condiments = []
def cook(self, time):
"""烤地瓜的方法"""
self.cook_time += time
if 0 <= self.cook_time < 3:
self.cook_static = '生的'
elif 3 <= self.cook_time < 5:
self.cook_static = '半生不熟'
elif 5 <= self.cook_time < 8:
self.cook_static = '熟了'
elif self.cook_time >= 8:
self.cook_static = '烤糊了'
def add_condiments(self, condiment):
"""添加调料"""
self.condiments.append(condiment)
def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}, 添加的调料有{self.condiments}'
digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
digua1.add_condiments('酱油')
print(digua1)
digua1.cook(2)
digua1.add_condiments('辣椒面儿')
print(digua1)
digua1.cook(2)
print(digua1)
digua1.cook(2)
print(digua1)
digua2 = SweetPotato()
digua2.cook(3)
print(digua2)
六. 综合应用—搬家具
5.1 需求
将小于房子剩余面积的家具摆放到房子中
5.2 步骤分析
需求涉及两个事物:房子 和 家具,故被案例涉及两个类:房子类 和 家具类。
(1) 定义类
-
房子类
- 实例属性
- 房子地理位置
- 房子占地面积
- 房子剩余面积
- 房子内家具列表
- 实例方法
- 容纳家具
- 显示房屋信息
- 实例属性
-
家具类
- 家具名称
- 家具占地面积
(2) 创建对象并调用相关方法
5.3 代码实现
(1) 定义类
家具类
class Furniture():
def __init__(self, name, area):
# 家具名字
self.name = name
# 家具占地面积
self.area = area
房子类
class Home():
def __init__(self, address, area):
# 地理位置
self.address = address
# 房屋面积
self.area = area
# 剩余面积
self.free_area = area
# 家具列表
self.furniture = []
def __str__(self):
return f'房子坐落于{self.address}, 占地面积{self.area}, 剩余面积{self.free_area}, 家具有{self.furniture}'
def add_furniture(self, item):
"""容纳家具"""
if self.free_area >= item.area:
self.furniture.append(item.name)
# 家具搬入后,房屋剩余面积 = 之前剩余面积 - 该家具面积
self.free_area -= item.area
else:
print('家具太大,剩余面积不足,无法容纳')
(3) 创建对象并调用实例属性和方法
bed = Furniture('双人床', 6)
jia1 = Home('北京', 1200)
print(jia1)
jia1.add_furniture(bed)
print(jia1)
sofa = Furniture('沙发', 10)
jia1.add_furniture(sofa)
print(jia1)
ball = Furniture('篮球场', 1500)
jia1.add_furniture(ball)
print(jia1)
5.4 代码总览
class Furniture():
def __init__(self, name, area):
# 家具名字
self.name = name
# 家具占地面积
self.area = area
class Home():
def __init__(self, address, area):
# 地理位置
self.address = address
# 房屋面积
self.area = area
# 剩余面积
self.free_area = area
# 家具列表
self.furniture = []
def __str__(self):
return f'房子坐落于{self.address}, 占地面积{self.area}, 剩余面积{self.free_area}, 家具有{self.furniture}'
def add_furniture(self, item):
"""容纳家具"""
if self.free_area >= item.area:
self.furniture.append(item.name)
# 家具搬入后,房屋剩余面积 = 之前剩余面积 - 该家具面积
self.free_area -= item.area
else:
print('家具太大,剩余面积不足,无法容纳')
bed = Furniture('双人床', 6)
jia1 = Home('北京', 1200)
print(jia1)
jia1.add_furniture(bed)
print(jia1)
sofa = Furniture('沙发', 10)
jia1.add_furniture(sofa)
print(jia1)
ball = Furniture('篮球场', 1500)
jia1.add_furniture(ball)
print(jia1)