当前位置:首页>python>【一起学 Python】第42天:OOP 三大特征之封装与私有属性

【一起学 Python】第42天:OOP 三大特征之封装与私有属性

  • 2026-09-09 16:55:04
【一起学 Python】第42天:OOP 三大特征之封装与私有属性

欢迎来到 Python 学习计划的第 42 天!🎉

恭喜你!今天我们完成了 OOP 核心阶段(第 39-42 天) 的最后一块拼图。前几天我们学习了 继承(代码复用)和 多态(接口统一),今天我们将探讨 封装(Encapsulation)。

封装是保护数据安全的盾牌,它决定了哪些内部细节应该对外隐藏,哪些接口应该对外暴露。理解私有属性和名称修饰机制,是编写健壮、安全代码的关键!

一、什么是封装(Encapsulation)?

1. 定义

封装 是指将数据(属性)和操作数据的方法(行为)绑定在一起,并隐藏对象的内部实现细节,只对外提供公开的访问接口。

2. 为什么要封装?

  • 数据安全:防止外部代码随意修改内部状态(如银行账户余额不能为负)。
  • 降低复杂度:使用者只需关心接口,无需了解内部如何实现。
  • 易于维护:内部实现改变不影响外部调用(只要接口不变)。

3. 比喻

  • 手机:你只需要知道按哪个键打电话(公开接口),不需要知道内部电路如何连接(隐藏细节)。
  • 胶囊:药物包裹在胶囊壳里,保护药物成分,控制释放。

二、访问控制:公有、保护与私有

Python 不像 Java 那样有严格的 public、protected、private 关键字,而是通过命名约定来实现访问控制。

修饰符

命名方式

访问权限

说明

公有 (Public)

var

任意访问

默认方式,内外均可访问

保护 (Protected)

_var

子类/内部

约定俗成,外部不应直接访问

私有 (Private)

__var

类内部

名称修饰,外部无法直接访问

1. 公有属性(默认)

任何人都可以访问和修改。

class Person:    def __init__(self, name):        self.name = name  # 公有属性p = Person("Alice")p.name = "Bob"  # ✅ 可以直接修改

2. 保护属性(单下划线)

约定俗成的私有,告诉开发者“这是内部用的,别在外面直接碰”。

class Person:    def __init__(self, name):        self._age = 18  # 保护属性p = Person("Alice")# p._age = 20  # ⚠️ 虽然能访问,但违反约定

3. 私有属性(双下划线)

强制私有。Python 会通过名称修饰(Name Mangling) 机制,让外部无法直接访问。

class BankAccount:    def __init__(self, balance):        self.__balance = balance  # 私有属性acc = BankAccount(1000)# print(acc.__balance)  # ❌ AttributeError: 无法直接访问

三、核心机制:名称修饰(Name Mangling)

1. 什么是名称修饰?

当类中出现 __var 形式的属性时,Python 解释器会自动将其重命名为 _ClassName__var。这是一种防止子类意外覆盖父类私有属性的机制。

2. 验证修饰效果

class Secret:    def __init__(self):        self.__password = "123456"s = Secret()# 直接访问失败# print(s.__password)  # ❌ AttributeError# 查看内部字典print(s.__dict__)  # 输出:{'_Secret__password': '123456'} (名字被改了!)# 强制访问(不推荐)print(s._Secret__password)  # ✅ 能访问,但破坏了封装性

3. 为什么这样设计?

  • 防止意外修改:避免外部代码随意更改关键数据。
  • 避免子类冲突:父类的 __var 和子类的 __var 会被修饰成不同的名字,互不干扰。
class Parent:    def __init__(self):        self.__var = "Parent"class Child(Parent):    def __init__(self):        super().__init__()        self.__var = "Child"  # 实际是 _Child__varc = Child()# 两个 __var 共存,互不影响

四、安全访问私有属性:Getter 与 Setter

既然私有属性不能直接访问,如何读取或修改?答案是提供公开方法。

1. 传统方法(Java 风格)

class BankAccount:    def __init__(self, balance):        self.__balance = balance    # Getter    def get_balance(self):        return self.__balance    # Setter (带验证)    def set_balance(self, amount):        if amount < 0:            raise ValueError("余额不能为负")        self.__balance = amountacc = BankAccount(1000)print(acc.get_balance())  # 1000acc.set_balance(2000)     # ✅ 安全修改# acc.set_balance(-100)   # ❌ 抛出异常

2. Pythonic 方式:@property(预告)

传统写法太繁琐。Python 提供了 @property 装饰器,让方法像属性一样调用。

💡 注意:@property 的高级用法我们将在 第 46 天 深入讲解,今天先了解概念。

class BankAccount:    def __init__(self, balance):        self.__balance = balance    @property    def balance(self):        return self.__balance    @balance.setter    def balance(self, amount):        if amount < 0:            raise ValueError("余额不能为负")        self.__balance = amountacc = BankAccount(1000)print(acc.balance)      # 像访问属性一样调用 getteracc.balance = 2000      # 像修改属性一样调用 setter

五、常见误区与注意事项

1. 私有不是绝对安全

名称修饰只是改了名字,有心人仍然可以通过 _ClassName__var 访问。Python 的私有是“君子协定”,主要防止意外修改,而非防黑客。

2. 不要滥用私有

  • 过度封装:把所有属性都私有化,导致类难以使用。
  • 建议:默认使用公有,只有在需要数据验证或防止误改时才用私有。

3. 子类无法直接访问父类私有属性

子类继承的是修饰后的名字,无法通过 __var 访问父类私有属性。

class Parent:    def __init__(self):        self.__var = "Parent"class Child(Parent):    def show(self):        # print(self.__var)  # ❌ 报错,找不到 _Child__var        print(self._Parent__var)  # ✅ 可以但不推荐

4. 特殊方法例外

以双下划线开头和结尾的方法(如 __init__, __str__)不是私有方法,而是魔法方法,不会被修饰。

六、实战练习

练习 1:实现安全的用户类

创建一个 User 类,包含:

  • 私有属性:__password (密码)
  • 公有属性:username (用户名)
  • 方法:set_password() (设置密码,要求长度至少 6 位), check_password() (验证密码)
class User:    def __init__(self, username, password):        self.username = username        self.__password = password    def set_password(self, new_pwd):        if len(new_pwd) < 6:            raise ValueError("密码长度至少 6 位")        self.__password = new_pwd    def check_password(self, pwd):        return self.__password == pwdu = User("alice", "123456")# u.set_password("123")  # ❌ 报错u.set_password("654321")  # ✅ 成功print(u.check_password("654321"))  # True

练习 2:探索名称修饰

创建一个类,定义私有属性 __secret,实例化后查看 __dict__,验证属性名是否被修饰。

class MyClass:    def __init__(self):        self.__secret = "Hidden"obj = MyClass()print(obj.__dict__)  # 输出包含 '_MyClass__secret': 'Hidden'# 验证访问# print(obj.__secret)  # ❌ 报错print(obj._MyClass__secret)  # ✅ 能访问(但不推荐)

七、总结

知识点

说明

封装

隐藏内部细节,提供公开接口,保护数据安全

公有属性

var,任意访问,默认方式

保护属性

_var,约定俗成,外部不应直接访问

私有属性

__var,名称修饰,外部无法直接访问

名称修饰

__var 自动变为 _ClassName__var

访问方式

通过公开方法(Getter/Setter)或 @property

最佳实践

默认公有,需验证时用私有,避免过度封装

🎉 OOP 核心阶段完结!

恭喜你!完成了 第 39-42 天 的 OOP 三大特征学习。你已经掌握了:

  • ✅ 继承:代码复用,建立层次关系
  • ✅ 多态:同一接口,不同实现,鸭子类型
  • ✅ 封装:隐藏细节,保护数据,私有属性

最新文章

随机文章