目录

📖 前言

第一章:封装 —— 类的“防护罩”

1.1 封装的本质

1.2 三种级别的直观对比

1.3 为什么要有封装?

第二章:属性(@property)—— 让方法“装”成数据

2.1 为什么要用属性?

2.2 @property + @xxx.setter 的基本用法

2.3 用 property() 函数的写法(对标你图中的代码)

2.4 属性封装的四个内置函数

🎯 一张图总结

🧁 结尾


📖 前言

面向对象有三大特性:封装、继承、多态。继承我们讲过了,今天聊另外两个合在一起的东西——封装 和 属性

封装,就是把数据“藏”起来,不让外面随便改。

属性,就是给封装开一扇“智能门”——外面看起来像在直接访问数据,其实背后偷偷走了你写的校验逻辑。

这俩加在一起,既保安全,又保好用。let us show !🛡️


第一章:封装 —— 类的“防护罩”

1.1 封装的本质

封装就是把类的内部数据藏好,只暴露必要的东西出去。

Python 里没有真正的“私有”,全靠命名约定来示意访问级别:

写法 级别 访问范围
self.name 公有(public) 任何地方都能访问
self._age 保护(protected) 类内和子类用,类外“不建议”用
self.__gender 私有(private) 只能在类内访问,外面访问会报错

1.2 三种级别的直观对比

看代码最清楚:

python

class Person:
    def __init__(self, name, age, gender):
        self.name = name          # ✅ 公有:谁都能访问
        self._age = age           # ⚠️ 保护:类内和子类用,外面别碰
        self.__gender = gender    # 🔒 私有:只有类内能访问

    def get_name(self):
        return self.name          # ✅ 类内访问公有

    def _get_age(self):
        return self._age          # ⚠️ 类内访问保护

    def __get_gender(self):
        return self.__gender      # 🔒 类内访问私有(可以)

    def show(self):
        # 类内:三种都能访问
        print(self.name, self._age, self.__gender)


class SuperPerson(Person):
    def show_sub(self):
        print(self.name)          # ✅ 子类可以访问父类的公有
        print(self._age)          # ⚠️ 子类可以访问父类的保护
        # print(self.__gender)    # ❌ 子类访问不了父类的私有!

# 测试
p = Person("张三", 30, "male")

# 类外访问
print(p.name)          # ✅ 张三(公有,随便看)
print(p._age)          # ⚠️ 30(保护,能看但最好别)
# print(p.__gender)    # ❌ AttributeError(私有,外面看不见)

# 子类测试
sp = SuperPerson("李四", 25, "female")
sp.show_sub()          # 能访问 name 和 _age,但访问不了 __gender

📌 一句话记死:单下划线 _ 是“约定”:请尊重我,别在外面碰我;双下划线 __ 是“强制”:Python 把它改名了,外面确实找不到。

1.3 为什么要有封装?

  1. 保护数据 —— 不让外面乱改关键数据

  2. 控制访问 —— 只暴露必要的方法,隐藏内部实现

  3. 降低耦合 —— 改里面不影响外面调用的代码

第二章:属性(@property)—— 让方法“装”成数据

2.1 为什么要用属性?

有时候你想在别人“取数据”或“改数据”的时候偷偷干点别的事——比如校验输入、打日志、触发更新。但你不想让调用者感受到“我是在调用方法”,希望他们觉得“我就是在直接访问一个数据”。

@property 就是干这个的——把方法伪装成属性。

2.2 @property + @xxx.setter 的基本用法

python

class Person:
    def __init__(self, name, age):
        self.__name = name   # 私有属性(双下划线,不让外面直接碰)
        self.__age = age

    # 获取属性:用 @property 装饰,调用时不用加括号
    @property
    def name(self):
        print("执行了获取函数")
        return self.__name

    # 设置属性:用 @属性名.setter 装饰
    @name.setter
    def name(self, value):
        print("执行了设置函数")
        if 2 <= len(value) <= 4:
            self.__name = value
        else:
            print("名字长度不合法,请保持在 2-4 个字符")

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):
        if 0 <= value <= 100:
            self.__age = value
        else:
            print("年纪不合法,请保持在 0-100 之间")

# 使用——看起来像在直接读写数据,其实背后走了校验逻辑
p = Person("张三", 20)

print(p.name)      # "执行了获取函数" → "张三"
p.name = "李四"    # 执行了设置函数(合法,会改)
p.name = "jleakogieskg"   # 不合法 → 名字长度不合法,不改
p.age = -66        # 年纪不合法,不改

📌 语法关键点

  • 上面:@property 负责“取值”(类似 getter

  • 下面:@age.setter 负责“赋值”(类似 setter

  • 名字必须一致,@property 的方法名 = @xxx.setter 的 xxx

2.3 用 property() 函数的写法(对标你图中的代码)

除了装饰器,还有另一种写法——用 property() 函数把 getter 和 setter 绑到一起:

python

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    # getter
    def __get_name(self):
        print("执行了获取函数")
        return self.__name

    # setter
    def __set_name(self, name):
        print("执行了设置函数")
        if 2 <= len(name) <= 4:
            self.__name = name
        else:
            print("名字长度不合法")

    def __get_age(self):
        return self.__age

    def __set_age(self, age):
        if 0 <= age <= 100:
            self.__age = age
        else:
            print("年纪不合法")

    # 用 property() 函数把 getter 和 setter 绑定成属性
    name = property(fget=__get_name, fset=__set_name)
    age = property(fget=__get_age, fset=__set_age)

p = Person("张三", 20)
print(p.name)    # 执行了获取函数 → 张三
p.name = "李四"  # 执行了设置函数

💡 property(fget=..., fset=...) 是装饰器写法的手动版。两种写法都能用,装饰器写法更常用,因为代码更直观、更简洁。

2.4 属性封装的四个内置函数

Python 提供了四个内置函数,方便你动态操作对象的属性:

python

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("张三", 20)

# hasattr:检查有没有这个属性
print(hasattr(p, "name"))     # True
print(hasattr(p, "salary"))   # False

# getattr:获取属性值(找不到可以给默认值)
print(getattr(p, "name"))     # 张三
print(getattr(p, "salary", 0)) # 0(找不到,返回默认值)

# setattr:设置属性值
setattr(p, "name", "李四")
print(p.name)                 # 李四

# delattr:删除属性
delattr(p, "age")
# print(p.age)                # ❌ AttributeError,已经被删了

🎯 一张图总结

text

封装:把数据藏起来,分三级权限
── 公有(name)    → 谁都能访问
── 保护(_name)   → 别在外面碰我(约定)
── 私有(__name)  → 只有类内能访问(强制改名)

属性:让方法伪装成数据
── @property         → 给“取值”加一层
── @xxx.setter       → 给“赋值”加一层(可加校验)
── 效果:p.name 像数据,背后却能走校验逻辑

四个内置函数:hasattr / getattr / setattr / delattr

🧁 结尾

到今天为止,封装和属性你就拿下了:

封装 —— 控制“谁能看到什么”,把数据藏好,只露该露的。

属性 —— 给数据访问加“智能门禁”,外面看起来像直接读/写,背后帮你做校验、打日志、触发更新。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐