12 面向对象封装案例
01.封装
- 封装是面向对象编程的一大特点
- 面向对象编程的第一步——将属性和方法封装到一个抽象的类中
- 外界使用类创建对象,然后让对象调用方法
- 对象方法的细节都被封装在类的内部
一个对象的 属性 可以 是另外一个类创建的对象
02.小明爱跑步
需求
1.小明体重75.0
公斤
2.小明每次跑步会减肥0.5
公斤
3.小明每次吃东西体重增加1
公斤
代码实现
提示:在对象方法的内部,是可以直接访问对象的属性的!
class Persion:
def __init__(self, name, weight):
# self.属性 = 形参
self.name = name
self.weight = weight
def __str__(self):
return "我的名字叫%s, 我的体重 %.2f 公斤" % (self.name, self.weight)
def run(self):
print("跑完步")
self.weight -= 0.5
def eat(self):
print("吃完东西")
self.weight += 1
xm = Persion("小明", 75.0)
xm.run()
xm.eat()
print(xm)
03 扩展—小红也爱跑步
需求
- 小明和小红都爱跑步
- 小明体重
75.0
公斤 - 小红体重
45.0
公斤 - 每次跑步都会减少
0.5
公斤 - 每次吃东西都会增加
1
公斤
提示:
- 在对象的方法内部,是可以直接访问对象的属性的
- 同一个类创建的多个对象之间,属性互不干扰
class Persion:
def __init__(self, name, weight):
# self.属性 = 形参
self.name = name
self.weight = weight
def __str__(self):
return "我的名字叫%s, 我的体重 %.2f 公斤" % (self.name, self.weight)
def run(self):
print("跑完步")
self.weight -= 0.5
def eat(self):
print("吃完东西")
self.weight += 1
xm = Persion("小明", 75.0)
xm.run()
xm.eat()
print(xm)
xh = Persion("小红", 45.0)
xh.run()
xh.eat()
print(xh)
04 摆放家具
需求:
-
房子有户型(House),总面积和家具名称列表
- 新房子没有任何的家具
-
家具(HouseItem)有名字,和占地面积,其中
- 席梦恩(bed)占地
4
平米 - 衣柜(chest)占地
2
平米 - 餐桌(table) 占地
1.5
平米
- 席梦恩(bed)占地
-
将以上三件家具添加到房子中
- 判断家具面积是否超过剩余面积,如果超过提示不能添加这件家具
- 将家具的名称追加到家具名称列表中
-
打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
- 用房子的剩余面积 - 家具的面积
# 家具类
HouseItem:
name
area
__init__(self, name, area):
__str__(self):
# 房子类
House:
house_type
area
free_area
item_list
__init__(self, house_type, area):
__str__(self):
add_item(self, item): # 添加家具
完整代码:
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return "[%s] 占地 %.2f 平米" % (self.name, self.area)
class House:
def __init__(self, house_type, area):
self.house_type = house_type
self.area = area
self.free_area = area
self.item_list = []
def __str__(self):
return ("户型:%s\n总面积:%.2f\n剩余面积:%.2f\n家具列表:%s"
% (self.house_type, self.area, self.free_area, self.item_list))
def add_item(self, item):
# 判断家具的面积
if item.area > self.free_area:
print("%s面过太大,无法添加" % item.name)
return
# 将家具名称添加到家具列表
self.item_list.append(item.name)
# 计算剩余面积
self.free_area -= item.area
bed = HouseItem("席梦思", 4)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 1.5)
print(bed)
print(chest)
print(table)
my_house = House("两室一厅", 60)
my_house.add_item(bed)
my_house.add_item(chest)
my_house.add_item(table)
print(my_house)
小结:
- 主程序只负责创建房子对象和家具对象
- 让房子对象调用
add_item
方法将家具添加到房子中 - 面积计算、剩余面积、家具列表等处理都被封装到房子类的内部
05 士兵突击
需求:
- 士兵 许三多 有一把
AK47
- 士兵可以开火
- 抢可以发射子弹
- 抢装填子弹 —— 增加子弹数量
类:Soldier GUN
属性:name model
gun bullet_count
__init__(self): __init__(self, model):
fire(self): add_bullet(self, count)
shoot(self):
枪类代码
class GUN:
def __init__(self, mode):
self.mode = mode
self.bullet_count = 0
def add_bullet(self, count):
self.bullet_count += count
def shoot(self):
# 判断子弹的数量
if self.bullet_count <= 0:
print("[%s] 没有子弹了。。。" % self.mode)
return
# 发射子弹计算剩余子弹
self.bullet_count -= 1
# 提示用户信息
print("[%s] 发射成功。。。[%d]" % (self.mode, self.bullet_count))
ak47 = GUN("ak47")
ak47.add_bullet(3)
ak47.shoot()
士兵类开发
假设每一个新兵都没有枪
定义没有初始值的属性
在定义属性时,如果不知道设置什么初始值,可以设置为 None
None
关键字表示什么都没有- 表示一个空对象,没有方法和属性,是一个特殊的变量
- 可以将
None
复制给任何一个变量
fire
方法需求
- 1> 判断是否有枪,没有强没法冲锋
- 2> 喊一声口号
- 3> 装填子弹
- 4> 射击
完整代码:
class GUN:
def __init__(self, mode):
self.mode = mode
self.bullet_count = 0
def add_bullet(self, count):
self.bullet_count += count
def shoot(self):
# 判断子弹的数量
if self.bullet_count <= 0:
print("[%s] 没有子弹了。。。" % self.mode)
return
# 发射子弹计算剩余子弹
self.bullet_count -= 1
# 提示用户信息
print("[%s] 发射成功。。。[%d]" % (self.mode, self.bullet_count))
class Soldier:
def __init__(self, name):
self.name = name
self.gun = None
def fire(self):
# 判断是否有枪
if self.gun is None:
print("[%s] 还没有抢" % self.name)
return
# 大喊口号
print("冲啊...[%s]" % self.name)
# 装填子弹
self.gun.add_bullet(50)
# 射击
self.gun.shoot()
ak47 = GUN("ak47")
xu = Soldier("许三多")
xu.gun = ak47
xu.fire()
06 身份运算符
身份运算符用于比较两个对象的内存地址是否一致——是否是对同一个对象的引用
- 在
Python
中针对None
比较时,建议使用is
判断
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用同一个对象 | x is y ,类似id(x)==id(y) |
is not | is not 是判断两个标识符是不是引用不同对象 | x is not y ,类似id(x)!=id(y) |
is
与==
的区别
is
用于判断两个变量引用对象是否为同一个
==
用于判断引用变量的值是否相等
In [1]: a = [1,2,3]
In [2]: a
Out[2]: [1, 2, 3]
In [3]: b = [1,2,3]
In [4]: id (a)
Out[4]: 139793827236464
In [5]: id (b)
Out[5]: 139793811716720
In [6]: a is b
Out[6]: False
In [7]: a == b
Out[7]: True
私有属性和私有方法
01 应用场景及定义方式
应用场景
- 在实际开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到
- 私有属性就是对象不希望公开的属性
- 私有方法就是对象不希望公开的方法
定义方式
- 在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性过方法
class Woman:
def __init__(self, name):
self.name = name
self.__age = 18
def __secret(self):
# 在对象内部的方法是可以直接访问对象内部的私有属性的
print("%s 的年龄是 %d" % (self.name, self.__age))
xiaofang = Woman("小芳")
# 私有属性在外界不能直接被访问
# print(xiaofang.__age)
# 私有方法同样不能在外界直接访问
# xiaofang.__secret()
02 伪私有属性和方法
提示:在日常开发中,不要使用这种方式,访问对象的私有属性或私有方法
python
中,并没有正真意义的私有
- 在给属性,方法命名时,实际是对名称做了一些特殊处理,使得外界无法访问到
- 处理方式:在名称前面加上
__类名
=_类名__名称
# 伪私有属性在外界不能直接被访问,可以这样访问
print(xiaofang._Woman__age)
# 伪私有方法不能在外界直接访问,可以这样访问
xiaofang._Woman__secret()