Skip to content

封装是什么 ​

封装就是把数据(属性)和操作数据的函数(方法)捆绑在一起,形成一个独立的单元(类),并隐藏内部的实现细节,只对外暴露必要的功能(方法)。

一句话:该让别人看的露出来,不该看的藏起来。

类属性与实例属性 ​

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() 返回脱敏后的名字(涛哥 → 涛**),既满足了外部需求,又不泄露完整信息。

相关 ​

练习题 ​

一、知识回顾(读完直接做下面的实践题) ​

  1. 封装就是把**数据(属性)和操作数据的函数(方法)**捆绑在一起,形成独立的类,并隐藏内部实现细节
  2. 所有实例共享的属性叫类属性(写在类体里、方法外);每个对象各有一份的叫实例属性(写在 __init__ 方法里)
  3. 私有属性/方法的名字前要加两个下划线 __;它们只能在类的内部使用
  4. Python 没有真正的私有机制,它只是一种约定
  5. 私有属性被改名后的形式是 _类名__属性名
  6. 想让外部安全地读取私有属性,正确做法是提供对外暴露的公共方法(如 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