目录
一、封装的概念与实现
封装是面向对象编程的三大特性之一(封装、继承、多态),它是面向对象编程的第一步,也是最重要的基础。
1.1 封装的核心概念
-
封装:将属性和方法封装到一个抽象的类中
-
使用方式:外界使用类创建对象,然后让对象调用方法
-
特点:对象方法的细节都被封装在类的内部,外界无需关心实现细节
1.2 封装示例:小智爱跑步
让我们通过一个"小智爱跑步"的案例来理解封装:
需求
-
小智 体重
75.0
公斤 -
小智每次 跑步 会减肥
0.5
公斤 -
小智每次 吃东西 体重增加
1
公斤
提示:在 对象的方法内部,是可以 直接访问对象的属性 的!
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return "我的名字叫 %s 体重 %.2f 公斤" % (self.name, self.weight)
def run(self):
"""跑步方法"""
print("%s 爱跑步,跑步锻炼身体" % self.name)
self.weight -= 0.5
def eat(self):
"""吃东西方法"""
print("%s 是吃货,吃完这顿再减肥" % self.name)
self.weight += 1
# 创建小智对象并测试
xiaozhi = Person("小智", 75)
xiaozhi.run()
xiaozhi.eat()
xiaozhi.eat()
print(xiaozhi)
代码解析:
-
Person
类封装了人的属性(name, weight)和行为(run, eat) -
外界只需要创建对象并调用方法,无需关心内部实现
-
在对象方法内部可以直接访问对象的属性
1.3 封装扩展:多对象互不干扰
同一个类创建的多个对象之间,属性互不干扰:
xiaozhi = Person("小智", 75)
xiaozhang = Person("小张", 45)
xiaozhi.run()
xiaozhang.eat()
print(xiaozhi)
print(xiaozhang)
二、封装实战:房屋与家具系统
2.1 需求分析
-
房子(House)有 户型、总面积 和 家具名称列表
(新房子没有任何家具) -
家具(HouseItem)有 名字 和 占地面积,其中
-
双人床(bed) 占地
4
平米 -
衣柜(chest) 占地
2
平米 -
餐桌(table) 占地
1.5
平米
-
-
在创建房子对象时,定义一个 剩余面积的属性,初始值和总面积相等
-
当调用
add_item
方法,向房间 添加家具 时,让 剩余面积 -= 家具面积 -
将以上三件 家具 添加 到 房子 中
-
打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
2.2 开发步骤
开发原则:先开发被使用的类(家具类),再开发使用它的类(房子类)
2.2.1 家具类实现
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return "[%s] 占地面积 %.2f" % (self.name, self.area)
# 创建家具对象
bed = HouseItem("双人床", 4)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 1.5)
print(bed)
print(chest)
print(table)
小结
-
创建了一个 家具类,使用到
__init__
和__str__
两个内置方法 -
使用 家具类 创建了 三个家具对象,并且 输出家具信息
2.2.2 房子类实现
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[剩余:%.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
# 使用示例
my_home = House("两室一厅", 60)
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)
小结
-
创建了一个 房子类,使用到
__init__
和__str__
两个内置方法 -
准备了一个
add_item
方法 准备添加家具 -
使用 房子类 创建了 一个房子对象
-
让 房子对象 调用了三次
add_item
方法,将 三件家具 以实参传递到add_item
内部
2.2.3 添加家具
需求
1> 判断 家具的面积 是否 超过剩余面积,如果超过,提示不能添加这件家具
2> 将 家具的名称 追加到 家具名称列表 中
3> 用 房子的剩余面积 - 家具面积
def add_item(self, item):
print("要添加 %s" % item)
# 1. 判断家具面积是否大于剩余面积
if item.area > self.free_area:
print("%s 的面积太大,不能添加到房子中" % item.name)
return
# 2. 将家具的名称追加到名称列表中
self.item_list.append(item.name)
# 3. 计算剩余面积
self.free_area -= item.area
小结
-
主程序只负责创建 房子 对象和 家具 对象
-
让 房子 对象调用
add_item
方法 将家具添加到房子中 -
面积计算、剩余面积、家具列表 等处理都被 封装 到 房子类的内部
三、私有属性与私有方法
3.1 私有成员的应用场景
-
某些属性或方法只希望在对象内部使用,不希望被外部访问
-
保护对象的某些敏感信息
-
隐藏实现细节,只暴露必要的接口
3.2 定义方式
在属性名或方法名前加两个下划线
__
:class Women: def __init__(self, name): self.name = name self.__age = 18 # 私有属性 def __secret(self): # 私有方法 print("我的年龄是 %d" % self.__age) xiaofang = Women("小芳") # xiaofang.__age # 报错,无法直接访问 # xiaofang.__secret() # 报错,无法直接调用
3.3 伪私有机制(了解即可)
Python中没有真正的私有,而是通过名称改写实现的伪私有:
print(xiaofang._Women__age) # 可以访问 xiaofang._Women__secret() # 可以调用
注意:在实际开发中,不建议使用这种方式访问私有成员,这破坏了封装原则。
四、总结
-
封装是面向对象编程的基础,它将属性和方法组织在类中
-
通过封装可以隐藏实现细节,只暴露必要的接口
-
私有属性和方法是封装的重要体现,保护对象内部状态
-
实际开发中应该遵循"最小暴露原则",只公开必要的内容
-