setattr 如何避免无限递归的防护写法

发布时间 - 2026-01-23 00:00:00    点击率:
setattr在自定义__setattr__中触发无限递归,因所有属性赋值均调用该方法;安全做法是直接操作self.__dict__[name] = value(无__slots__时)或调用object.__setattr__(self, name, value)。

为什么 setattr 在自定义 __setattr__ 里会触发无限递归

当你在类的 __setattr__ 方法内部直接调用 setattr(self, name, value),Python 会再次进入同一个 __setattr__,形成死循环。这不是 bug,而是机制:所有属性赋值(包括 self.x = ysetattr(self, ...))都会走 __setattr__

标准防护写法:绕过自定义逻辑,直写实例字典

最常用、最安全的方式是跳过 __setattr__,把值直接写进实例的 __dict__

def __setattr__(self, name, value):
    if name == "special_flag":
        # 自定义逻辑
        super().__setattr__(name, value.upper())  # 或其他处理
    else:
        # 防护:不触发 __setattr__,避免递归
        self.__dict__[name] = value
  • self.__dict__[name] = value 是底层字典操作,完全绕过 __setattr__
  • 适用于大多数普通属性;但对使用 __slots__ 的类不生效(此时需用 object.__setattr__(self, name, value)
  • 注意:如果类有 property 或描述符,这种写法会跳过它们的 setter,只写入实例字典 —— 这正是你想要的「绕过」行为

替代方案:用 object.__setattr__ 显式委托

当类继承链复杂,或你希望保持与父类 __setattr__ 行为一致(比如父类做了验证),应显式调用基类实现:

def __setattr__(self, name, value):
    if name == "counter":
        if not isinstance(value, int):
            raise TypeError("counter must be int")
        # 委托给 object.__setattr__,不触发当前类重写的 __setattr__
        object.__setattr__(self, name, value)
    else:
        super().__setattr__(name, value)  # 或继续委托给父类
  • object.__setattr__(self, name, value) 是 Python 属性赋值的最终实现,不经过任何自定义 __setattr__
  • self.__dict__ 更通用:兼容 __slots__、描述符、property setter(只要它们没被覆盖)
  • 不要写成 super().__setattr__(...) —— 如果父类也重写了 __setattr__,仍可能递归

容易踩的坑:你以为绕过了,其实没绕开

以下写法看似“手动”,实则仍在触发 __setattr__

  • self.name = value → 触发当前 __setattr__
  • setattr(self, name, value) → 触发当前 __setattr__
  • self.__dict__.update({name: value}) → 看似字典操作,但某些情况下(如 __dict__ 被代理或封装)可能间接触发
  • __init__ 中未做防护就调用 setattr → 同样递归,因为 __init__self.x = y 也会走 __setattr__

真正安全的只有两种:

直接操作 self.__dict__(无 __slots__ 时),或明确调用 object.__setattr__。其余都是幻觉。


# python  # ai  # 为什么 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 利用JavaScript实现拖拽改变元素大小  Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面  成都网站制作公司哪家好,四川省职工服务网是做什么用?  在Oracle关闭情况下如何修改spfile的参数  WordPress 子目录安装中正确处理脚本路径的完整指南  创业网站制作流程,创业网站可靠吗?  如何用IIS7快速搭建并优化网站站点?  如何用wdcp快速搭建高效网站?  Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布  Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】  英语简历制作免费网站推荐,如何将简历翻译成英文?  公司门户网站制作流程,华为官网怎么做?  如何用低价快速搭建高质量网站?  java中使用zxing批量生成二维码立牌  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  如何在服务器上三步完成建站并提升流量?  如何在万网开始建站?分步指南解析  Laravel如何使用Livewire构建动态组件?(入门代码)  黑客入侵网站服务器的常见手法有哪些?  Python文件异常处理策略_健壮性说明【指导】  如何续费美橙建站之星域名及服务?  如何自定义建站之星模板颜色并下载新样式?  如何在万网利用已有域名快速建站?  标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析  Android 常见的图片加载框架详细介绍  ,南京靠谱的征婚网站?  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  Laravel如何为API生成Swagger或OpenAPI文档  北京网站制作公司哪家好一点,北京租房网站有哪些?  如何用免费手机建站系统零基础打造专业网站?  如何在阿里云部署织梦网站?  Laravel策略(Policy)如何控制权限_Laravel Gates与Policies实现用户授权  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  香港网站服务器数量如何影响SEO优化效果?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  公司网站制作价格怎么算,公司办个官网需要多少钱?  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  jQuery 常见小例汇总  Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能  百度浏览器网页无法复制文字怎么办 百度浏览器复制修复  猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】  如何在万网自助建站中设置域名及备案?  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  Laravel如何使用Telescope进行调试?(安装和使用教程)  太平洋网站制作公司,网络用语太平洋是什么意思?  历史网站制作软件,华为如何找回被删除的网站?  JavaScript如何实现路由_前端路由原理是什么  Laravel如何升级到最新版本?(升级指南和步骤)  Android仿QQ列表左滑删除操作  Laravel Vite是做什么的_Laravel前端资源打包工具Vite配置与使用