@property仅控制属性读取,不定义setter时赋值会报AttributeError;要拦截赋值必须显式定义同名@xxx.setter并在其中校验,否则可直接操作私有字段绕过防护。

@property 本身不提供安全访问,它只是把方法伪装成属性;真正的“安全”取决于你如何在 getter/setter 中做校验和封装。
为什么直接用 @property 无法防住绕过?
Python 没有私有属性机制,_name 或 __name 都能被外部直接赋值。比如:
class User:
def __init__(self, name):
self._name = name
<pre class='brush:python;toolbar:false;'>@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str) or not value.strip():
raise ValueError("name must be a non-empty string")
self._name = value.strip()u = User("Alice") u.name = "Bob" # ✅ 走 setter,校验生效 u._name = "" # ❌ 直接改 _name,完全绕过校验 u._User__name = "!" # ❌ 即使双下划线,也能被访问
所以,@property 的防护是“约定型”的——它只对走属性访问路径的代码起作用。
什么时候该用 @property 而不是普通方法?
适合用于:计算属性、带逻辑的读写、兼容旧接口、隐藏内部表示。不适合用于高频调用或含 I/O 的场景。
立即学习“Python免费学习笔记(深入)”;
- ✅ 合理:将
full_name封装为@property,避免每次调用都拼接字符串 - ✅ 合理:把
age设为只读属性,基于_birth_date动态计算 - ❌ 不合理:把一个要查数据库的
latest_order做成@property,调用者意识不到性能开销 - ❌ 不合理:用
@property实现复杂状态机切换,语义不清且难以测试
怎么让 @property 更可靠一点?
靠文档 + 约定 + 辅助手段,不能靠语法强制:
- 用单下划线前缀(如
_email)明确表示“请勿直读直写”,并在 docstring 里写清必须通过email属性访问 - 在
__init__和 setter 中做完整校验,比如邮箱格式、长度限制、枚举值检查 - 需要强约束时,可配合
__slots__禁止动态添加属性,减少误操作可能 - 单元测试里显式测
obj._email = "bad"是否导致后续obj.email行为异常,验证封装是否被破坏
真正难的不是写 @property,而是判断哪些字段值得封装、哪些校验必须放进去、以及团队是否理解并遵守这个隐式契约。


















