python类中的__setattr__

1. 基本用法

默认情况下,Python 自动处理属性赋值。但你可以重写 setattr 来拦截赋值。

class A:def __setattr__(self, name, value):super().__setattr__(name, value)

2. 必须使用 super().setattr 才能真正赋值

错误写法(会无限递归):

def __setattr__(self, name, value):self.x = value   # ❌ 再次触发 __setattr__,无限递归

正确写法:

super().__setattr__(name, value)

3. 常见用途

3.1 属性验证

class Person:def __setattr__(self, name, value):if name == "age" and value < 0:raise ValueError("age cannot be negative")super().__setattr__(name, value)

3.2 自动类型转换或格式化

class Config:def __setattr__(self, name, value):if name == "path":value = value.replace("\\", "/")super().__setattr__(name, value)

3.3 禁止动态新增属性

class Locked:allowed = {"x", "y"}def __setattr__(self, name, value):if name not in self.allowed:raise AttributeError(f"Cannot add new attribute: {name}")super().__setattr__(name, value)

3.4 记录属性赋值(日志用途)

class Monitor:def __setattr__(self, name, value):super().__setattr__(name, value)

4. 与 getattr / getattribute 的关系

方法 触发时机 说明
setattr 属性赋值时 控制 obj.x = v
getattr 找不到属性时 后备属性查找
getattribute 所有属性访问时 最底层拦截器
delattr 删除属性时 控制 del obj.x

setattr 只负责 设置,而另两个负责 获取。

5. 常见错误(必须避免)

5.1 在内部使用 self.x = ...(导致递归)

def __setattr__(self, name, value):self.x = value    # ❌ 无限递归

5.2 忘记写

super().__setattr__

导致属性根本不会被保存。

6.保存需要插入数据库的列(用这个可以避免影响这些列)

        #sampleself.name = 'a'self.attrs = copy.copy(obj._attrs)self.gui_name = 'a'

通过控制self.attrs = copy.copy(obj._attrs)的位置分割需要插数据库和不需要插数据库的属性,obj._attrs在__setattr__方法中增加需要插入数据库的列名,后续修改属性时使用super().__setattr__确保attrs不受影响。