真正影响对象生命周期的魔术方法是__new__、__enter__、__exit__和__del__;其中__enter__/__exit__是资源清理的可靠入口,__new__用于实例化前控制,__del__不保证执行时机。

__init__ 之外,哪些魔术方法真正影响对象生命周期
对象创建后立刻被销毁、或在上下文管理中意外中断,往往不是逻辑错误,而是没补全关键魔术方法。比如 __del__ 并不保证执行时机,而 __enter__ 和 __exit__ 才是资源清理的可靠入口。
常见错误现象:ResourceWarning: unclosed file 或数据库连接泄漏,多数因只写了 __init__ 分配资源,却没配对实现上下文协议。
-
__new__在实例化前介入,适合单例、类型控制(如返回子类实例),但别在里面做耗时操作 -
__del__不要依赖它释放关键资源;它可能在解释器关闭时才触发,甚至不触发 - 若对象需自动释放(文件、锁、网络连接),必须同时实现
__enter__和__exit__,且__exit__要显式处理异常传播(返回True表示吞掉异常)
__eq__ 和 __hash__ 不配对会导致字典/集合行为异常
自定义类放进 set 或作为 dict 键时突然“消失”或重复,大概率是重写了 __eq__ 却忘了同步调整 __hash__。
Python 规则很硬:只要 __eq__ 被重写,默认 __hash__ 就设为 None,导致实例不可哈希——此时往 set 里加会报 TypeError: unhashable type。
立即学习“Python免费学习笔记(深入)”;
citySHOP是一款集CMS、网店、商品、分类信息、论坛等为一体的城市多用户商城系统,已完美整合目前流行的Discuz! 6.0论坛,采用最新的5.0版PHP+MYSQL技术。面向对象的数据库连接机制,缓存及80%静态化处理,使它能最大程度减轻服务器负担,为您节约建设成本。多级店铺区分及联盟商户地图标注,实体店与虚拟完美结合。个性化的店铺系统,会员后台一体化管理。后台登陆初始网站密匙:LOVES
- 若对象逻辑上“可变”,应显式设
__hash__ = None,避免误用 - 若对象逻辑“不可变”(如坐标点、配置项),
__hash__应基于参与__eq__判等的字段计算,例如return hash((self.x, self.y)) - 注意浮点字段慎入
__hash__:float('nan')的哈希值未定义,会导致集合操作崩溃
__str__ vs __repr__ 混用会干扰调试和日志可读性
日志里打印出一串 <__main__.dataobject object at>,或者 REPL 中显示一堆无意义字符串,说明这两个方法没按角色分工。
__repr__ 是给开发者看的,目标是“能还原对象”;__str__ 是给用户看的,目标是“好读”。两者输出差异太大,会导致调试时信息缺失,太小又让终端输出难理解。
-
__repr__应包含类名和关键属性,格式尽量接近构造调用,例如DataPoint(x=1.2, y=3.4) -
__str__可简化,甚至返回自然语言描述,例如"Point at (1.2, 3.4)" - 如果类没有业务含义(如纯数据容器),可直接让
__str__ = __repr__,但别反过来
__getattr__ 和 __getattribute__ 选错会引发无限递归
一加 __getattr__ 就报 RecursionError: maximum recursion depth exceeded,通常是误用了 __getattribute__,或在其中访问了自身属性。
区别很关键:__getattribute__ 拦截所有属性访问(包括 __dict__、方法),而 __getattr__ 只在属性查找不到时才触发。
- 想做“属性代理”或“动态字段 fallback”,优先用
__getattr__,安全且轻量 - 非要用
__getattribute__(比如统一审计字段访问),必须用super().__getattribute__(name)获取原始值,绝不能直接写self.xxx - 在
__getattr__里抛异常时,别再触发自己——例如访问self.__dict__是安全的,但self.some_missing_attr会再次进__getattr__
__hash__ 和 __eq__ 的绑定关系,以及 __getattribute__ 中绕过父类访问的写法。这两处一旦出错,问题往往延迟暴露,排查成本远高于初期多写两行。





