前言
大家好,我是倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!!!
如果你照着 Java 的习惯写下 __secret
,却发现 obj._ClassName__secret
依然随手可破,那一刻你会怀疑:Python 的"私有"是不是一场大型行为艺术?
没错------Python 故意不给你真正的私有属性,而下划线只是它留下的礼貌性遮羞布。
为什么 Guido 宁被骂也要拆掉"private"这堵墙?
1970 年代的 ABC 语言是 Guido 的启蒙老师。ABC 里所有变量默认全局可见,社区却奇迹般地没有因此陷入混乱。
这段经历在 Guido 心里埋下一颗种子:"信任程序员"比"防范程序员"更有长远收益。
1989 年圣诞节,当他写下 Python 的第一行语法时,干脆把"访问控制"整个模块从语言层面删掉------既没 private
,也没 protected
。
留下的,只有一条后来写进 PEP 8 的文化约定 :前缀单下划线 _name
代表"内部实现",双下划线 __name
只是触发名字改写(name mangling),物理路径仍在,只是换了个尴尬的全名。
于是出现了让 Java 程序员当场脑溢血的场景:
python
class Wallet:
def __init__(self):
self.__cash = 100
w = Wallet()
print(w._Wallet__cash) # 100,毫无阻碍
Python 文档毫不避讳地承认:"This is not a security mechanism." 换句话说,它连假装上锁都懒得装。
"我们都是成年人"------Python 之禅里的自由主义毒药
在 import this
输出的 19 条禅语里,有一句杀伤力极大:
"We are all consenting adults here."
这句话源自 2001 年 comp.lang.python 的一场口水仗。当有人提议加入真正的 private
时,社区大佬们集体反对:与其用语法枷锁,不如用社会契约。
毕竟,隐藏实现细节的真正目的不是防贼,而是减少误用。如果你铁了心要破坏封装,语言又何必浪费字节做无效拦截?
这种"成年人"哲学让 Python 形成了独特的代码气味识别系统:看到单下划线,你会自觉远离;看到双下划线,你知道这是作者的最后通牒。
违反约定?可以,但请自负骂名。
于是,Python 把"封装"从编译器检查下沉到了程序员道德自律------一种更柔性、却也更高效的社会化约束。
历史包袱:从 CPython 源码到 PyObject 的裸奔结构
深入到 CPython 源码,你会发现所有对象都是一个裸体的 PyObject
:
c
typedef struct _object {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
没有任何访问标志位。字段的可见性全靠约定俗成 :想访问?直接 obj->ob_type
,没人拦你。
这种极简设计并非偷懒,而是 1990 年代早期为了跨语言嵌入 做的妥协。Python 需要能被 C 随意"掏内脏",一旦加上访问控制,C 扩展模块就得写一堆 getter/setter,性能与复杂度双崩。
Guido 索性一不做二不休:让所有属性裸奔,换取解释器与 C 世界的无缝互操作。
当 @property
成为遮羞布,哲学伤口依旧在渗血
没有真私有,副作用很快显现:库作者想隐藏内部状态,却只能用下划线吓唬用户,结果依旧被误用。
于是 2.2 版本引入 @property
,试图用语法糖模拟"只读字段":
python
class Wallet:
def __init__(self):
self._cash = 100
@property
def cash(self):
return self._cash
看似优雅,实则治标不治本。
obj._cash
仍然合法,甚至因为 @property
的存在,误用者会误以为 _cash
是稳定接口。
更严重的是,@property
带来了隐蔽的性能税:每次访问都触发一次 Python 函数调用,比直接字段慢 3~5 倍。
在追求极限性能的场景,开发者不得不拆掉 @property
,重新裸奔------亲手把遮羞布撕掉。
社区分裂:dataclass 的 frozen 与"私有"的暧昧共舞
到了 3.7 的 dataclass,官方又试图用 frozen=True
做"不可变"封装:
python
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
表面禁止赋值,实际依旧能被 object.__setattr__
暴力破解:
python
p = Point(1, 2)
object.__setattr__(p, 'x', 999) # 毫无阻拦
历史一再重演 :Python 始终拒绝在语法层面承认"私有"。
这导致了一个尴尬局面:
- 库作者想要真正的封装 → 只能依赖文档恐吓
- 性能敏感者想要裸字段 → 不敢用
@property
- 新手被双下划线误导 → 以为真有魔法盾
未来会不会有真的 private?Guido 的退休留言
2021 年,Guido 在 PyCon US 的"退休访谈"中被问到这个问题,他笑着回答:
"If we ever add real private, I'd have to come back from retirement just to veto it."
全场哄笑,却也宣告了一个时代的终章:Python 的哲学立场不可动摇------与其用语法砌墙,不如用社区文化做护城河。
这种选择让 Python 失去了"企业级"最爱的硬性封装,却换来了代码的极度透明与可调试性。
当你能一眼看穿框架的内脏,定位 bug 的快感会抵消所有"私有"焦虑。
最后感谢阅读!欢迎关注我,微信公众号 :
倔强青铜三
。欢迎点赞
、收藏
、关注
,一键三连!!!