目录
📖 前言
第一章:封装 —— 类的“防护罩”
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
🧁 结尾
到今天为止,封装和属性你就拿下了:
封装 —— 控制“谁能看到什么”,把数据藏好,只露该露的。
属性 —— 给数据访问加“智能门禁”,外面看起来像直接读/写,背后帮你做校验、打日志、触发更新。


