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.保存需要插入数据库的列(用这个可以避免影响这些列)

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

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

posted @ 2025-11-16 15:27  哒令,哒哒哒哒哒~令  阅读(15)  评论(0)    收藏  举报