Python 封装与属性:类的“防护罩”和“智能门禁”
目录
📖 前言
第一章:封装 —— 类的“防护罩”
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 为什么要有封装?
保护数据—— 不让外面乱改关键数据
控制访问—— 只暴露必要的方法,隐藏内部实现
降低耦合—— 改里面不影响外面调用的代码
第二章:属性(@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
🧁 结尾
到今天为止,封装和属性你就拿下了:
封装—— 控制“谁能看到什么”,把数据藏好,只露该露的。
属性—— 给数据访问加“智能门禁”,外面看起来像直接读/写,背后帮你做校验、打日志、触发更新。