
在 python 中,`@property` 的公开名称(如 `name`)应不带下划线,而其底层存储字段(如 `_name`)必须加单下划线前缀——这是有意为之的设计:前者是受控接口,后者是私有实现细节,二者职责分离,不可混用。
在定义带属性控制的类时,正确区分 name(属性名)与 _name(存储名)是保障封装性与可维护性的关键。正如 Real Python 教程中所示:
class Employee:
def __init__(self, name, birth_date, start_date):
self.name = name # ✅ 调用 property setter
self.birth_date = birth_date
self.start_date = start_date
@property
def name(self):
return self._name # ✅ 读取私有存储字段
@name.setter
def name(self, value):
self._name = value.upper() # ✅ 写入私有存储字段,含业务逻辑此处 self.name = name 在 __init__ 中并非“绕过”属性,而是主动利用属性机制完成初始化——它确保了所有赋值(无论来自构造函数还是外部代码)都统一经过 setter,从而强制执行大写转换逻辑。若改为直接写 self._name = name.upper(),则会导致逻辑重复、违反 DRY 原则,且一旦后续修改校验规则(如增加长度限制或正则验证),极易遗漏构造函数中的硬编码逻辑。
⚠️ 注意事项:单下划线 _name 是约定俗成的“受保护”标识,表示该字段仅供类内部(特别是对应 property 的 getter/setter)使用,不应在类外或子类中直接访问或修改;绝对避免在 __init__ 或其他方法中混用 self.name(走 property)和 self._name(直写),否则会破坏一致性;若需在类内复用存储逻辑(如 __repr__ 中引用),仍应通过 self.name 访问,而非 self._name,以保持接口统一;@property 本质是描述符(descriptor),其行为由 Python 数据模型自动触发——obj.name 触发 getter,obj.name = x 触发 setter,与普通属性访问语法一致,但语义完全不同。
这种设计体现了 Python 的核心哲学:“显式优于隐式,简单优于复杂”。公开接口(name)简洁直观,实现细节(_name)清晰隔离,既保证了灵活性,又杜绝了误用风险。










