封装是什么
封装就是把数据(属性)和操作数据的函数(方法)捆绑在一起,形成一个独立的单元(类),并隐藏内部的实现细节,只对外暴露必要的功能(方法)。
一句话:该让别人看的露出来,不该看的藏起来。
类属性与实例属性
python
class Car:
# 类属性:所有实例对象共享的
wheel = 4 # 轮胎数量
tax_rate = 0.1 # 购置税税率
def __init__(self, c_color, c_brand, c_name):
# 实例属性:每个对象各自一份
self.color = c_color
self.brand = c_brand
self.name = c_name
def start(self):
print(f'{self.brand} {self.name} 正在启动...')
def stop(self):
print(f'{self.brand} {self.name} 停止行驶...')| 类型 | 写在哪 | 特点 |
|---|---|---|
| 类属性 | 类体里、方法外 | 所有实例共享(如 wheel = 4) |
| 实例属性 | __init__ 里用 self.xxx | 每个对象各有一份(如 self.color) |
私有属性与私有方法
python
class Car:
def __init__(self, c_color, c_brand, c_name, c_owner):
self.color = c_color
self.brand = c_brand
self.name = c_name
self.__owner = c_owner # 私有属性:名字前加 __
def start(self):
print(f'{self.brand} {self.name} 正在启动...')
def run(self):
print(f'{self.__owner} : {self.brand} {self.name} 正在行驶...')
self.__control_fuel() # 类的内部可以调用私有方法
def __control_fuel(self): # 私有方法:名字前加 __
print(f'{self.brand} {self.name} 正在控制燃油分配...')
def get_owner(self): # 对外暴露一个"脱敏"的读取方式
return self.__owner[0:1] + "**"| 公共属性/方法 | 私有属性/方法 | |
|---|---|---|
| 定义方式 | 直接写名字 | 名字前加 两个下划线 __ |
| 类的内部 | 可以访问 | 可以访问 |
| 类的外部 | 可以访问 | 不能访问 |
| 应用场景 | 对外功能 | 不想对使用者公开的内部实现 |
IMPORTANT
Python 中并没有真正的私有机制,只是"约定":名字前加 __ 的属性会被改名成 _类名__属性名,所以在外面写 car._Car__owner 依然能访问到——但不要这么干,那等于绕过约定。
TIP
私有属性不是"藏起来就完事",而是要提供安全的对外接口。比如例子里的 get_owner() 返回脱敏后的名字(涛哥 → 涛**),既满足了外部需求,又不泄露完整信息。
相关
练习题
一、知识回顾(读完直接做下面的实践题)
- 封装就是把**数据(属性)和操作数据的函数(方法)**捆绑在一起,形成独立的类,并隐藏内部实现细节
- 所有实例共享的属性叫类属性(写在类体里、方法外);每个对象各有一份的叫实例属性(写在
__init__方法里) - 私有属性/方法的名字前要加两个下划线
__;它们只能在类的内部使用 - Python 没有真正的私有机制,它只是一种约定
- 私有属性被改名后的形式是
_类名__属性名 - 想让外部安全地读取私有属性,正确做法是提供对外暴露的公共方法(如
get_owner())
二、裸写题
- 提示(先自己想,实在想不出再点开)
一级 · 思路:余额设为私有,只通过方法修改和读取 二级 · 方法:
self.__balance在__init__里初始化 三级 · 骨架:def deposit(self, amount): self.__balance += amount- 参考答案(做完再点开)
python# 2-1 class BankAccount: def __init__(self, card, balance): self.__card = card # 私有:卡号 self.__balance = balance # 私有:余额 def deposit(self, amount): if amount <= 0: print("存款金额必须大于 0") return self.__balance += amount print(f"存款成功,当前余额:{self.__balance}") def get_balance(self): return self.__balance account = BankAccount("6222021234567890", 100) account.deposit(50) print(account.get_balance()) # 150- 提示(先自己想,实在想不出再点开)
一级 · 思路:直接用点号访问私有属性会报错,但加上类名前缀就"绕"过去了 二级 · 方法:
account.__balance(报 AttributeError)/account._BankAccount__balance三级 · 骨架:用try/except捕获 AttributeError 打印提示- 参考答案(做完再点开)
python# 2-2:私有并不真私有 try: print(account.__balance) except AttributeError as e: print("直接访问私有属性失败:", e) # 报错 print(account._BankAccount__balance) # 150(能"绕"进去,但不建议这么做)- 提示(先自己想,实在想不出再点开)
一级 · 思路:私有属性做到"内部完整、对外脱敏" 二级 · 方法:字符串切片
card[-4:]三级 · 骨架:return "****" + self.__card[-4:]- 参考答案(做完再点开)
python# 2-3 class BankAccount: def __init__(self, card, balance): self.__card = card # 私有:卡号 self.__balance = balance # 私有:余额 def deposit(self, amount): if amount <= 0: print("存款金额必须大于 0") return self.__balance += amount print(f"存款成功,当前余额:{self.__balance}") def get_balance(self): return self.__balance def get_card_info(self): # 脱敏接口 return "****" + self.__card[-4:] account = BankAccount("6222021234567890", 100) print(account.get_card_info()) # ****7890
